1

I wonder if it's possible to create my own str_replace, to fill in the blank see example below:

$words = array('cat','mole');
$find='[blank]';
$string ="Lorem ipsum -[blank]- sit amet, consectetur
                        adipiscing elit. Donec condimentum augue 
                        sit amet blandit vehicula. Nullam placerat
                        aliquam dictum. Quisque elementum nisl
                        sed pellentesque elementum. Aliquam erat
                        volutpat. Suspendisse potenti. Maecenas [blank]." 
echo str_replace ($find,$words,$string);

the expected out put would be this:

Lorem ipsum -cat- sit amet, consectetur
adipiscing elit. Donec condimentum augue 
sit amet blandit vehicula. Nullam placerat
aliquam dictum. Quisque elementum nisl
sed pellentesque elementum. Aliquam erat
volutpat. Suspendisse potenti. Maecenas mole.

thanks

edit: if i can improve this question i would it hard to explain so i given a example instead.

chris85
  • 23,846
  • 7
  • 34
  • 51
TheDeveloper
  • 890
  • 1
  • 15
  • 37
  • 3
    You are TheDeveloper. You should know that everything is possible ;) – Niels Dec 01 '17 at 19:26
  • @Niels well not entirely true, some thing are a mystery – TheDeveloper Dec 01 '17 at 19:29
  • You can create any function you want...not sure why `$words` is an array though and find isn't, but that's a beauty of php, most functions were created after the fact – Forbs Dec 01 '17 at 19:31
  • 1
    using `preg_replace_callback()`; you'll need to escape the $find with `preg_quote()` and then jut keep a count of which elements from $words have already been replaced, probably using `%` to cycle back through in case you find more $finds than there are $words in the array – Mark Baker Dec 01 '17 at 19:33
  • Sounds similar to https://stackoverflow.com/questions/47378516/php-replace-dynamic-content-based-on-position-in-string/47378849#47378849. – chris85 Dec 01 '17 at 19:34

2 Answers2

4

Brief

A super simple way of doing this is simply iterating over the array and setting preg_replace to only replace 1 item (instead of every match). Another method uses string functions to find position of $needle in $haystack as adapted from this answer.


Code

Both methods below assume that $haystack is the input. Sample input (copied from OP's question) below:

$haystack = <<<DOC
Lorem ipsum -[blank]- sit amet, consectetur
adipiscing elit. Donec condimentum augue 
sit amet blandit vehicula. Nullam placerat
aliquam dictum. Quisque elementum nisl
sed pellentesque elementum. Aliquam erat
volutpat. Suspendisse potenti. Maecenas [blank].
DOC;

Using regex

If your $needle is unknown in the sense that it can possibly contain special regex characters, you can use preg_quote to escape these special characters (as noted by musashii in the comments below my answer).

See code in use here

$array = ['cat', 'mole'];
$re = '/\[blank\]/';

foreach($array as $replacement) {
    $text = preg_replace($re, $replacement, $haystack, 1);
}

echo $haystack;

Using string functions

See code in use here

$array = ['cat', 'mole'];
$needle = '[blank]';

foreach($array as $replacement) {
    $pos = strpos($haystack, $needle);
    if ($pos !== false) {
        $haystack = substr_replace($haystack, $replacement, $pos, strlen($needle));
    }
}

echo $haystack;
ctwheels
  • 21,901
  • 9
  • 42
  • 77
  • you can use `preg_quote` for the needle `$string= preg_replace("~".preg_quote($needle)."~", $replace, $string,1);` – musashii Dec 01 '17 at 19:48
  • +1 dangit, I was about to post the non-regex thing you added. Minor optimizations to that would be getting the length of needle once outside the loop and breaking if needle isn't found. – Don't Panic Dec 01 '17 at 19:53
  • @Don'tPanic sorry! I stole the answers haha – ctwheels Dec 01 '17 at 19:55
  • @Jan ya I realize this only works well on a small subset. There's definitely room for optimizations, but I wanted to keep it simple to give the general idea of how to achieve the expected result. – ctwheels Dec 01 '17 at 21:59
  • @Jan you put that in your answer, so I'll leave that one for you :) – ctwheels Dec 01 '17 at 22:03
0

Another one could be to use preg_replace_callback and a closure:

$cnt = 0;
$regex = '~\Q[blank]\E~';
$string = preg_replace_callback(
    $regex,
    function($match) use ($cnt, $words) {
        global $cnt;
        if (array_key_exists($cnt, $words)) {
            $cnt++;
            return $words[$cnt-1];
        } else {
            return '';
        }
    },
    $string);
echo $string;

This yields

Lorem ipsum -cat- sit amet, consectetur
adipiscing elit. Donec condimentum augue 
sit amet blandit vehicula. Nullam placerat
aliquam dictum. Quisque elementum nisl
sed pellentesque elementum. Aliquam erat
volutpat. Suspendisse potenti. Maecenas mole.


Idea is to increase a counter $cnt and return the value of the array $words.
The regular expression
~\Q[blank]\E~

just means [blank] without escaping it.

Jan
  • 42,290
  • 8
  • 54
  • 79
  • thanks, even more interesting approach. Any performance downfall here, in comparisons to `substr_replace` and `strpos` – TheDeveloper Dec 02 '17 at 19:49