Replace preg_replace() e modifier with preg_replace_callback
我很讨厌正则表达式。 我正在尝试替换为:
1 2 3 | public static function camelize($word) { return preg_replace('/(^|_)([a-z])/e', 'strtoupper("\\2")', $word); } |
与带有匿名函数的preg_replace_callback一起使用。 我不知道\ 2在做什么。 或就此而言,preg_replace_callback的工作方式完全一样。
实现该目标的正确代码是什么?
在正则表达式中,您可以使用
相反,
所以
1 | 'do_stuff(\\1) ."and" . do_stuff(\\2)' |
可能成为
1 | function($m) { return do_stuff($m[1]) ."and" . do_stuff($m[2]); } |
还是你的情况
1 | 'strtoupper("\\2")' |
可能成为
1 |
请注意,
1 2 3 4 | 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'); |
与任何函数一样,默认情况下,您无法在回调之外(从周围的范围)访问变量。使用匿名函数时,可以使用
1 | 'do_stuff(\\1, $foo)' |
那么新的回调可能看起来像
1 | function($m) use ($foo) { return do_stuff($m[1], $foo); } |
陷阱
-
使用
preg_replace_callback 代替了正则表达式上的/e 修饰符,因此您需要从"模式"参数中删除该标志。因此,像/blah(.*)blah/mei 这样的模式将变成/blah(.*)blah/mi 。 -
/e 修饰符在内部在参数上使用了addslashes() 的变体,因此某些替代使用stripslashes() 删除了它。在大多数情况下,您可能希望从新的回调中删除对stripslashes 的调用。
带评估功能的preg_replace垫片
这是非常不可取的。但是,如果您不是程序员,或者真的不喜欢糟糕的代码,则可以使用替代的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | /** * Can be used as a stopgap shim for preg_replace() calls with /e flag. * Is likely to fail for more complex string munging expressions. And * very obviously won't help with local-scope variable expressions. * * @license: CC-BY-*.*-comment-must-be-retained * @security: Provides `eval` support for replacement patterns. Which * poses troubles for user-supplied input when paired with overly * generic placeholders. This variant is only slightly stricter than * the C implementation, but still susceptible to varexpression, quote * breakouts and mundane exploits from unquoted capture placeholders. * @url: https://stackoverflow.com/q/15454220 */ function preg_replace_eval($pattern, $replacement, $subject, $limit=-1) { # strip /e flag $pattern = preg_replace('/(\W[a-df-z]*)e([a-df-z]*)$/i', '$1$2', $pattern); # warn about most blatant misuses at least if (preg_match('/\(\.[+*]/', $pattern)) { trigger_error("preg_replace_eval(): regex contains (.*) or (.+) placeholders, which easily causes security issues for unconstrained/user input in the replacement expression. Transform your code to use preg_replace_callback() with a sane replacement callback!"); } # run preg_replace with eval-callback return preg_replace_callback( $pattern, function ($matches) use ($replacement) { # substitute $1/$2/… with literals from $matches[] $repl = preg_replace_callback( '/(?<!\\\\)(?:[$]|\\\\)(\d+)/', function ($m) use ($matches) { if (!isset($matches[$m[1]])) { trigger_error("No capture group for '$m[0]' eval placeholder"); } return addcslashes($matches[$m[1]], '"\'\`\$\\\0'); # additionally escapes '$' and backticks }, $replacement ); # run the replacement expression return eval("return $repl;"); }, $subject, $limit ); } |
本质上,您只需在代码库中包含该函数,然后编辑
到使用
利弊:
- 真的只是用Stack Overflow的一些样本进行了测试。
- 仅支持简单情况(函数调用,不支持变量查找)。
- 包含更多限制和咨询通告。
- 对于表达式失败,将产生错位且难以理解的错误。
-
但是,这仍然是一个可用的临时解决方案,不会使向
preg_replace_callback 的正确过渡复杂化。 - 许可证注释只是为了防止人们过度使用或传播过多此类许可证。
替换代码生成器
现在,这有点多余。但是可能会帮助那些仍然不知所措的用户
手动将其代码重构为
要使用此功能,请将任何损坏的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | /** * Use once to generate a crude preg_replace_callback() substitution. Might often * require additional changes in the `return …;` expression. You'll also have to * refit the variable names for input/output obviously. * * >>> preg_replace_eval_replacement("/\w+/", 'strtopupper("$1")', $ignored); */ function preg_replace_eval_replacement($pattern, $replacement, $subjectvar="IGNORED") { $pattern = preg_replace('/(\W[a-df-z]*)e([a-df-z]*)$/i', '$1$2', $pattern); $replacement = preg_replace_callback('/[\'"]?(?<!\\\\)(?:[$]|\\\\)(\d+)[\'"]?/', function ($m) { return"\$m[{$m[1]}]"; }, $replacement); $ve ="var_export"; $bt = debug_backtrace(0, 1)[0]; print"[cc lang="php"] #---------------------------------------------------- # replace preg_*() call in '$bt[file]' line $bt[line] with: #---------------------------------------------------- \$OUTPUT_VAR = preg_replace_callback( {$ve($pattern, TRUE)}, function (\$m) { return {$replacement}; }, \$YOUR_INPUT_VARIABLE_GOES_HERE ) #---------------------------------------------------- |
n";
}
code> pre>
请注意,仅复制粘贴不是编程。您必须将生成的代码改编回实际的输入/输出变量名称或使用上下文。
-
特别是,如果在
if 中使用了先前的preg_replace 调用,则必须去$OUTPUT = 分配。 - 最好还是保留临时变量或多行代码块结构。
并且替换表达式可能需要更多的可读性改进或返工。
-
例如,
stripslashes() 通常在文字表达式中变得多余。 -
变量范围查找需要在回调中使用
use 或global 引用。 -
用引号括起来的
"-$1-$2" 捕获引用在语法上最终会被普通转换为"-$m[1]-$m[2] 破坏。
代码输出仅仅是一个起点。是的,这作为在线工具会更加有用。这种代码重写方法(编辑,运行,编辑,编辑)有些不切实际。对于习惯以任务为中心的编码(更多的步骤,更多的发现)的人来说,它可能更容易接近。因此,这种替代方法可能会减少一些重复的问题。
您不应该使用标志
您也可以使用T-Regx库
1 | pattern('(^|_)([a-z])')->replace($word)->by()->group(2)->callback('strtoupper'); |