PHP preg_match_all搜索和替换

时间:2014-07-28 01:55:32

标签: php regex search replace preg-match

我已经尝试了大约一百万个不同的正则表达式,我无法绕过这一个(不可否认,很多正则表达式都不在我的掌握之中)。

在我的文中我有这样的变量:

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

我有一个包含所有替换的数组('one'的索引是'one'等),但有些可能会丢失。

如果数组存在,我想从数组中替换,如果没有,则单独保留文本。

我可以使用什么正则表达式来preg_match_all下面的代码段中的$ text中的变量,在适当的地方替换$ replace并回显到浏览器?

<?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

此:

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

就像在片段中一样,是我得到的最接近的。

它也必须使用变量名中的do。

提前感谢所有帮助!

4 个答案:

答案 0 :(得分:8)

这是使用preg_replace_callback()的一个非常好的案例,但首先让我们改进你的正则表达式:

  1. 摆脱e修饰符,不推荐使用它,因为我们要使用preg_replace_callback()

    ,所以您不需要它
    /\{\{\$(\w+)\}\}/
    
  2. 在这种情况下我们不需要逃避{{}},PCRE 智能足以说明它们不是量词的

    /{{\$(\w+)}}/
    
  3. 由于输入中有点,我们需要更改\w,否则它将永远不会匹配。 [^}]是完美的,因为它意味着匹配除}

    之外的任何内容
    /{{\$([^}]+)}}/
    
  4. 我倾向于使用不同的分隔符,这不是必需的:

    #{{\$([^}]+)}}#
    
  5. 让我们认真开展业务,use identifier在这里会有很大的帮助:

    $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

答案 1 :(得分:3)

您不需要使用正则表达式,因为您只处理固定字符串:

$replaces = array('testa.testb.testc' => 1, 'testc.testa' => 2, 'testf' => 3);
$keys = array_map(function ($item) {
    return '{{$' . $item . '}}'; }, array_keys($replaces));
$trans = array_combine($keys, $replaces);

$result = strtr($text, $trans);

请注意,如果您像这样编写替换数组,则不需要array_map

$trans = array('{{$testa.testb.testc}}' => 1, '{{$testc.testa}}' => 2, '{{$testf}}' => 3);

答案 2 :(得分:2)

您只是使用$matches而不是$matches[0],这就是您发布的代码不起作用的原因。

你的正则表达式不会将.\w一起计算,所以让我们试试[\w.]+

(我使用$matches[1]直接包含我们需要的密钥,然后我们不需要使用str_replace 2次了)

$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;

这有效并且返回:

1
2
3
{{$aaaaa}}

答案 3 :(得分:0)

您还可以使用具有自动定界符的T-Regx library

使用replace()->by()->mapIfExists()

$output = pattern('{{\$([^}]+)}}')
    ->replace('{{$testa.testb.testc}}<br>{{$testc.testa}}<br>{{$testf}}<br>{{$aaaaa}}<br>')
    ->all()
    ->by()
    ->group(1)
    ->mapIfExists([
       'testa.testb.testc' => '1', 
       'testc.testa' => '2',
       'testf' => '3'
    ]);
});

echo $output;

此代码完全执行@HamZa答案,但使用T-Regx:)