用preg_replace_callback替换preg_replace()e修饰符

问题描述 投票:81回答:1

我对正则表达式很糟糕。我试图取代这个:

public static function camelize($word) {
   return preg_replace('/(^|_)([a-z])/e', 'strtoupper("\\2")', $word);
}

使用带有匿名函数的preg_replace_callback。我不明白\\ 2是做什么的。或者就此而言preg_replace_callback的工作原理。

实现这一目标的正确代码是什么?

php regex preg-replace preg-replace-callback
1个回答
72
投票

在正则表达式中,您可以使用(brackets)“捕获”匹配字符串的一部分;在这种情况下,你正在捕捉比赛的(^|_)([a-z])部分。这些编号从1开始编号,因此您有后引用1和2.匹配0是整个匹配的字符串。

/e修饰符采用替换字符串,并用反斜杠替换后跟一个数字(例如\1)和适当的反向引用 - 但因为你在一个字符串中,你需要转义反斜杠,所以你得到'\\1'。然后(有效地)运行eval来运行生成的字符串,好像它是PHP代码(这就是为什么它被弃用,因为它很容易以不安全的方式使用eval)。

preg_replace_callback函数接受一个回调函数,并传递一个包含匹配的反向引用的数组。那么你在哪里编写'\\1',而是访问该参数的元素1 - 例如如果你有一个function($matches) { ... }形式的匿名函数,那么该函数内的第一个反向引用是$matches[1]

所以/e的论点

'do_stuff(\\1) . "and" . do_stuff(\\2)'

可能成为回调

function($m) { return do_stuff($m[1]) . "and" . do_stuff($m[2]); }

或者在你的情况下

'strtoupper("\\2")'

可能成为

function($m) { return strtoupper($m[2]); }

请注意,$m$matches不是魔术名称,它们只是我在声明我的回调函数时给出的参数名称。此外,您不必传递匿名函数,它可以是函数名称作为字符串,或者某种形式的array($object, $method)as with any callback in PHP,例如

function stuffy_callback($things) {
    return do_stuff($things[1]) . "and" . do_stuff($things[2]);
}
$foo = preg_replace_callback('/([a-z]+) and ([a-z]+)/', 'stuffy_callback', 'fish and chips');

与任何函数一样,默认情况下,您无法访问回调之外的变量(来自周围的范围)。使用匿名函数时,可以使用use关键字导入需要访问的变量as discussed in the PHP manual。例如如果旧的论点是

'do_stuff(\\1, $foo)'

然后新的回调可能看起来像

function($m) use ($foo) { return do_stuff($m[1], $foo); }

Gotchas

  • 在正则表达式中使用preg_replace_callback而不是/e修饰符,因此您需要从“模式”参数中删除该标志。因此像/blah(.*)blah/mei这样的模式将成为/blah(.*)blah/mi
  • /e修饰符在参数内部使用了addslashes()的变体,因此一些替换使用stripslashes()来删除它;在大多数情况下,您可能希望从新回调中删除对stripslashes的调用。
© www.soinside.com 2019 - 2024. All rights reserved.