Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP preg_match_all search and replace

I have tried about a million different regexes and I just can't wrap my head around this one (admittedly a lot of regex is out of my grasp).

In my text I have variables like this:

{{$one}}
{{$three.four.five}}
{{$six.seven}}

And I have an array with all the replaces for them (the index for 'one' is 'one' etc) but some may be missing.

I want to replace from the array if it exists and if not leave the text alone.

What regex can I use to preg_match_all of the variables in $text in the snippet below, replace from $replace where appropriate and echo out to the browser?

<?php
    $replaces = array('testa.testb.testc' => '1', 'testc.testa' => '2', 'testf' => '3');
    $text = '{{$testa.testb.testc}}<br>{{$testc.testa}}<br>{{$testf}}<br>{{$aaaaa}}<br>';

    preg_match_all('/\{\{\$(\w+)\}\}/e', $text, $matches);

    foreach($matches as $match)
    {
        $key = str_replace('{{$', '', $match);
        $key = str_replace('}}', '', $key);

        if(isset($replaces[$key]))
            $text = str_replace($match, $replaces[$key], $text);
    }

    // I want to end up echo'ing:
    //   1<br>2<br>3<br>{{$aaaaa}}<br>

    echo $text;
?>

http://codepad.viper-7.com/4INvEE

This:

'/\{\{\$(\w+)\}\}/e'

like in the snippet, is the closest I have gotten.

It has to work with the does in the variable names too.

Thanks in advance for all the help!

like image 301
Alex Howe Avatar asked Jul 28 '14 01:07

Alex Howe


People also ask

What is the difference between Preg_match and Preg_match_all?

preg_match stops looking after the first match. preg_match_all , on the other hand, continues to look until it finishes processing the entire string. Once match is found, it uses the remainder of the string to try and apply another match.

What is Preg_match_all in PHP?

The preg_match_all() function returns the number of matches of a pattern that were found in a string and populates a variable with the matches that were found.

What is the difference between Preg_replace and Str_replace?

str_replace replaces a specific occurrence of a string, for instance "foo" will only match and replace that: "foo". preg_replace will do regular expression matching, for instance "/f. {2}/" will match and replace "foo", but also "fey", "fir", "fox", "f12", etc.


2 Answers

This is a very good case for using preg_replace_callback() but first let's polish your regex:

  1. Get rid of the e modifier, it's deprecated and you don't need it since we're going to use preg_replace_callback()

    /\{\{\$(\w+)\}\}/
    
  2. We don't need to escape {{}} in this case, PCRE is smart enough to tell that they are not meant as quantifiers

    /{{\$(\w+)}}/
    
  3. Since you got dots in your input, we need to change \w otherwise it will never match. [^}] is perfect since it means match anything except }

    /{{\$([^}]+)}}/
    
  4. I tend to use different delimiters, this is not required:

    #{{\$([^}]+)}}#
    

Let's get to serious business, the use identifier is going to be of great help here:

$replaces = array('testa.testb.testc' => '1', 'testc.testa' => '2', 'testf' => '3');
$text = '{{$testa.testb.testc}}<br>{{$testc.testa}}<br>{{$testf}}<br>{{$aaaaa}}<br>';

$output = preg_replace_callback('#{{\$([^}]+)}}#', function($m) use ($replaces){
    if(isset($replaces[$m[1]])){ // If it exists in our array
        return $replaces[$m[1]]; // Then replace it from our array
    }else{
        return $m[0]; // Otherwise return the whole match (basically we won't change it)
    }
}, $text);

echo $output;

Online regex demo Online php demo

like image 154
HamZa Avatar answered Sep 22 '22 14:09

HamZa


Well you are just using $matches and not $matches[0], that's why the code you posted does not work.

And your regex doesn't count the . with the \w, so let'z try with [\w.]+

(I used $matches[1] that contains directly the key we need, and then we don't need to use str_replace 2 times more)

$replaces = array('testa.testb.testc' => '1', 'testc.testa' => '2', 'testf' => '3');
$text = '{{$testa.testb.testc}}<br>{{$testc.testa}}<br>{{$testf}}<br>{{$aaaaa}}<br>';

preg_match_all('/\{\{\$([\w.]+)\}\}/', $text, $matches);

var_dump($matches[1]);

foreach($matches[1] as $match)
{
    if(isset($replaces[$match]))
    {
        $text = str_replace('{{$'.$match.'}}', $replaces[$match], $text);
    }
}

echo $text;

This works and returns :

1
2
3
{{$aaaaa}}
like image 31
Bobot Avatar answered Sep 22 '22 14:09

Bobot