用preg_replace_callback替换preg_replace()e修饰符

Cas*_*sey 82 php regex preg-replace preg-replace-callback

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

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

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

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

IMS*_*SoP 73

在正则表达式中,您可以"捕获"匹配字符串的一部分(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)'
Run Code Online (Sandbox Code Playgroud)

可能成为回调

function($m) { return do_stuff($m[1]) . "and" . do_stuff($m[2]); }
Run Code Online (Sandbox Code Playgroud)

或者在你的情况下

'strtoupper("\\2")'
Run Code Online (Sandbox Code Playgroud)

可能成为

function($m) { return strtoupper($m[2]); }
Run Code Online (Sandbox Code Playgroud)

需要注意的是$m$matches不是魔法的名字,他们只是说出我的回调函数,当我把参数名称.此外,您不必传递匿名函数,它可以是函数名称作为字符串,或者某种形式array($object, $method),就像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');
Run Code Online (Sandbox Code Playgroud)

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

'do_stuff(\\1, $foo)'
Run Code Online (Sandbox Code Playgroud)

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

function($m) use ($foo) { return do_stuff($m[1], $foo); }
Run Code Online (Sandbox Code Playgroud)

陷阱

  • 使用preg_replace_callback不是/e对正则表达式的修改,所以你需要从你的"模式"的说法删除该标志.所以这样的模式/blah(.*)blah/mei就会变成/blah(.*)blah/mi.
  • 所述/e改性剂中使用的变体addslashes()内部的参数,所以一些替代用于stripslashes()将其取出; 在大多数情况下,您可能希望stripslashes从新回调中删除调用.