【问题标题】:preg_replace arrays with multiple patterns per replacement每次替换具有多个模式的 preg_replace 数组
【发布时间】:2017-12-21 10:52:25
【问题描述】:

我不认为我可以在一个 swell foop 中做到这一点,但我并没有超过要求 :-)

我当然可以定义一对一的$pattern$replacement 数组,我可以重复定义$pattern 数组和$replacement 字符串,但我可以同时定义吗?

假设我有三组:

$p1 = array('sis','boom','bah');
$r1 = 'cheers';

$p2 = array('boo','hiss');
$r2 = 'jeers';

$p3 = array('guinness','heineken','budweiser');
$r3 = 'beers';

我想在一个大干草堆中用它们各自的单个替换替换所有模式实例。我可以定义一个 preg_replace 调用来完成此操作吗?

【问题讨论】:

  • 如果您使用正则表达式,您可以在模式中使用(sis|boom|bah),否则 str_replace 可以获取一组值进行搜索并替换为单个值。
  • str_replace() 不会考虑字边界,当在另一个子字符串中找到子字符串时,可能会返回意外结果。
  • 要完全暴露不包括单词边界的问题......如果你有$string='My sister paid 500 baht for a boomerang';并使用echo preg_replace('/sis|boom|bah/','cheers',$string);,那么你会得到这个混乱的混乱:My cheerster paid 500 cheerst for a cheerserang虽然没有预期的替代品制作。

标签: php arrays preg-replace


【解决方案1】:

我认为您需要将单词边界与基于正则表达式的函数合并。

考虑这个strtr() 演示:

$string="Rah rah, sis boom bah, I read a book on budweiser";
$p1 = array('sis','boom','bah');
$r1 = 'cheers';
$p2 = array('boo','hiss');
$r2 = 'jeers' ;
$p3 = array('guinness','heineken','budweiser');
$r3 = 'beers';

$replacements=array_merge(
    array_combine($p1,array_fill(0,sizeof($p1),$r1)),
    array_combine($p2,array_fill(0,sizeof($p2),$r2)),
    array_combine($p3,array_fill(0,sizeof($p3),$r3))
);
echo strtr($string,$replacements);

输出:

Rah rah, cheers cheers cheers, I read a jeersk on beers
//                                      ^^^^^ Oops

您只需要使用管道内爆 needle 元素并将它们包装在一个非捕获组中,以便单词边界适用于所有子字符串,如下所示:

代码:(Demo)

$string="Rah rah, sis boom bah, I read a book on budweiser";
$p1 = ['sis','boom','bah'];
$r1 = 'cheers';
$p2 = ['boo','hiss'];
$r2 = 'jeers' ;
$p3 = ['guinness','heineken','budweiser'];
$r3 = 'beers';
$find=['/\b(?:'.implode('|',$p1).')\b/','/\b(?:'.implode('|',$p2).')\b/','/\b(?:'.implode('|',$p3).')\b/'];
$swap=[$r1,$r2,$r3];
var_export($find);
echo "\n";
var_export($swap);
echo "\n";
echo preg_replace($find,$swap,$string);

输出:

array (
  0 => '/\\b(?:sis|boom|bah)\\b/',                 // unescaped: /\b(?:sis|boom|bah)\b/
  1 => '/\\b(?:boo|hiss)\\b/',                     // unescaped: /\b(?:boo|hiss)\b/
  2 => '/\\b(?:guinness|heineken|budweiser)\\b/',  // unescaped: /\b(?:guinness|heineken|budweiser)\b/
)
array (
  0 => 'cheers',
  1 => 'jeers',
  2 => 'beers',
)
Rah rah, cheers cheers cheers, I read a book on beers

*备注:

单词边界\b 确保整个单词匹配,避免意外的不匹配。

如果您需要不区分大小写,只需在每个正则表达式模式的末尾使用 i 标志即可。例如/\b(?:sis|boom|bah)\b/i

【讨论】:

  • 啊哈!是的,将每个模式数组更改为单个正则表达式会再次将其降低到 1:1。这有点痛苦,但 implode() 是一个很酷的技巧,它再次使这个程序化。我期待更多的想法,但是当我明天再看时,这可能会得到复选标记:-) 谢谢!
【解决方案2】:
$subject = 'sis + boo + guinness';
echo preg_replace(['/sis|boom|bah/','/boo|hiss/','/guinness|heineken|budweiser/'],['cheers','jeers','beers'],$subject);
// the result would be cheers + jeers + beers

替换 字符串或带有要替换的字符串的数组。如果这个参数是 字符串和模式参数是一个数组,所有模式都将是 替换为该字符串。如果模式和替换参数 是数组,每个模式都会被替换 对方。如果替换数组中的元素少于 在模式数组中,任何额外的模式都将被替换为空的 细绳。 ...

如果 subject 是一个数组,则搜索和替换在 subject的每一项,返回值也是一个数组。

【讨论】:

  • boo 更改为book 时,您的方法会产生意外结果。 sandbox.onlinephpfunctions.com/code/… 查看我关于单词边界的回答。
  • @mickmackusa,在$subject = 'sis + book + guinness'; 上面的链接中导致cheers + jeersk + beers 这是正常的预期行为,
  • 如果您只想替换整个单词 boo 而不是 book 的开头,请不要这样做 明白我的意思吗?
猜你喜欢
  • 2011-09-27
  • 2014-07-12
  • 1970-01-01
  • 2015-05-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-08-14
  • 2023-03-15
相关资源
最近更新 更多