用strtr同时替换字母

时间:2015-09-04 02:15:00

标签: php regex replace preg-replace strtr

我正在尝试用strtr同时替换字符串,但我遇到了一个问题。如果同时更换的字母与另一个同时被替换的字母相邻,则不会替换第一个字母后面的字母。我该怎么做才能解决这个问题?感谢。

$text = " no bacon cats nobody ";
$text = strtr($text, array(" no " => " bacon ", " bacon " => " no ", " cats " => " dogs "));
echo $text;

预期结果

bacon no dogs nobody

实际结果

bacon bacon dogs nobody
P.S:我必须确保这些词不是另一个词的一部分。这就是为什么白色空间在那里。例如,单词“no”是“nobody”的一部分,如果你在字符串中替换了所有“no”,它也会替换像“nobody”这样的单词;

2 个答案:

答案 0 :(得分:5)

那么这里会发生什么?

$text = " a b c ";
$text = strtr($text, array(" a " => " b ", " b " => " a ", " c " => " d "));

首先你必须知道:

  1. 最长的键将首先被替换
  2. 更换后,它不再搜索此密钥
  3. 所以这里所有键都具有相同的长度,意味着它将替换第一个key => value元素,然后是第二个,依此类推。

    首先替换" a " => " b ",这将更改您的起始字符串:

     a b c 
    ↑↑↑ Match
    

    到此:

     b b c
    ↑↑↑ Replacement
    

    还记得我们怎么说,在替换它之后它不再搜索它了吗?究竟!现在它搜索" b " => " a ",但只搜索字符串的这一部分:

     a b c 

    所以它找不到它,因为b前面没有空间可以搜索。这就是为什么你没有得到预期的输出。并且会再次找到c,因为它前面有一个空格。

    因此,代码中的问题是,它在搜索下一个键时不包含替换值。即使[space]b[space]在您的字符串中,它也找不到它,因为第一个空格来自键[space]a[space]的替换值,它不会包含在下一个搜索中。

    修改

    从您更新的问题来看,似乎您已经这样做,试图阻止单词成为其他单词的一部分。要解决这个问题,只需创建一个查找数组并使用带有单词boundarys的preg_replace_callback()来匹配完整的单词而不仅仅是它的一部分,例如。

    <?php
    
        $text = " apple bacon cats ";
        $replacement = ["apple" => "bacon", "bacon" => "apple", "cats" => "dogs"];
        $search = array_map(function($v){
            return preg_quote($v, "/");
        }, array_keys($replacement));
    
        echo $text = preg_replace_callback("/\b(" . implode("|", $search) . ")\b/", function($m)use($replacement){
            return $replacement[$m[1]];
        }, $text);
    
    ?>
    

答案 1 :(得分:0)

没有strtr的方式:

$text = 'no bacon cats nobody';
$rep = ['no'=>'bacon', 'bacon'=>'no', 'cats'=>'dogs'];

$parts = explode(' ', $text);
foreach ($parts as &$part) {
    if (isset($rep[$part]))
        $part = $rep[$part];
}

$result = implode(' ', $parts);

如果您想要更灵活的内容,请将explode行替换为:

$parts = preg_split('~\b~', $parts);

并使用implode的空字符串。