【问题标题】:Replacing part of string with prefix and suffix用前缀和后缀替换部分字符串
【发布时间】:2021-06-25 14:49:23
【问题描述】:
$str = ' I love [123] and [124] at (456). I hate [234] and [235] at (123).'

我想做

$str = 'I love <a title="a">[123]</a> and <a title="b">[124]</a> at <a title="XX">(456)</a>. I hate <a title="c">[234]</a> and <a title="d">[235]</a> at <a title="ZZ">(123)</a>.'

要替换的文本是大括号 () 或 [] 中的,可从表 1 或表 2 中找到。

Table 1
123 | a
124 | b
234 | c
235 | d

Table 2
456 | XX
123 | ZZ

目前的方法

$text=explode(' ', $text);
for ($i=0; $i<count($text); $i++) {
    for ($j=0; $j<count($table1Col1); $j++) {
        if ($text[$i] == $table1Col1[$j])
            $text[$i] = '<a href="#" title="'.$table1Col2[$j].'">'.$table1Col1[$j].'</a>';
    }
    for ($j=0; $j<count($table2Col1); $j++) {
        if ($text[$i] == $table2Col1[$j])
            $text[$i] = '<a href="#" title="'.$table2Col2[$j].'">'.$table2Col1[$j].'</a>';
    }
}

如何改进代码以跳过不需要的循环?

【问题讨论】:

  • 所以[]只适用于table1,()适用于table2?
  • @AbraCadaver 是的!

标签: php string replace str-replace


【解决方案1】:

我可能会考虑一种使用循环的方法,但由于数组具有相同的键,它们无法合并:

foreach($table1Col1 as $find => $repl) {
    $text = str_replace("[$find]",
                        "<a title=\"$repl\">[$find]</a>",
                        $text);
}

foreach($table1Col2 as $find => $repl) {
    $text = str_replace("($find)",
                        "<a title=\"$repl\">($find)</a>",
                        $text);
}

【讨论】:

    【解决方案2】:

    也许,preg_replace_callback 在这里会更好?

    $str = 'I love [123] and [124] at (456). I hate [234] and [235] at (123).';
    $t1 = ['123'=>'a', '124'=>'b', '234'=>'c', '235'=>'d'];
    $t2 = ['456'=>'XX', '123'=>'ZZ'];
    
    
    $f1 = implode('|', array_map(fn ($k) => preg_quote($k), array_keys($t1)));
    $f2 = implode('|', array_map(fn ($k) => preg_quote($k), array_keys($t2)));
    
    $res = preg_replace_callback("/\[($f1)\]|\(($f2)\)/", function($m) use($t1, $t2) {
      // if first group has matched, then found key will be in `$m[1]`
      // if second group has matched, then found key will be in `$m[2]`
      $m1 = $m[1] ?? null;
      $m2 = $m[2] ?? null;
      if ($m1) {
        // use first table
        return '<a title="'.$t1[$m1].'">['.$m1.']</a>';
      }
      // use second table
      return '<a title="'.$t2[$m2].'">('.$m2.')</a>';
    }, $str);
    

    结果:

    I love <a title="a">[123]</a> and <a title="b">[124]</a> at <a title="XX">(456)</a>. I hate <a title="c">[234]</a> and <a title="d">[235]</a> at <a title="ZZ">(123)</a>.
    

    【讨论】:

      【解决方案3】:

      假设字符串中的所有值都存在于表中,您可以使用替换 | 来捕获 2 组中的每个数字,并使用 preg_replace_callback 使用组值对数组进行索引。

      \[(\d+)]|\((\d+)\)
      

      Regex demo | Php demo

      $str = ' I love [123] and [124] at (456). I hate [234] and [235] at (123).';
      $table1Col1=["123" => "a", "124" => "b", "234" => "c", "235" => "d"];
      $table1Col2 = ["456" => "XX", "123" => "ZZ"];
      $pattern = "/\[(\d+)]|\((\d+)\)/";
      
      $result = preg_replace_callback($pattern, function($match) use ($table1Col1, $table1Col2) {
          return sprintf('<a title="%s">%s</a>',
              array_key_exists(2, $match) ? $table1Col2[$match[2]] : $table1Col1[$match[1]]
              , $match[0]
          );
      }, $str);
      
      echo $result;
      

      输出

       I love <a title="a">[123]</a> and <a title="b">[124]</a> at <a title="XX">(456)</a>. I hate <a title="c">[234]</a> and <a title="d">[235]</a> at <a title="ZZ">(123)</a>.
      

      【讨论】:

      • 您的解决方案将表格限制为仅使用数字键,并且不处理不存在的键。
      • @Styx 在示例数据中,键是数字,这就是它以Assuming all the values in the string are present in the table开头的原因
      • 对,对不起,没注意到这一行。
      • @Styx 没有问题,如果可以有其他字符,那么模式可以是例如\[([^][]+)]|\(([^()])\)
      • 仍然认为搜索精确表的键更好。虽然我喜欢你使用sprintf,但没想到:)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-03-24
      • 2014-06-12
      • 2021-09-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多