【发布时间】:2011-04-16 13:20:03
【问题描述】:
当在 PHP 中使用 preg_replace() 并在运行时生成字符串时,可以使用 preg_quote() 保护搜索字符串中的特殊正则表达式字符(例如 '$' 或 '+')。但是在替换字符串中处理这个的正确方法是什么?以这段代码为例:
<?php
$haystack = '...a bit of sample text...';
$replacement = '\\HELLO WORLD$1.+-';
$replacement_quoted = preg_quote($replacement);
var_dump('--replacement', $replacement, '--replacement_quoted',
$replacement_quoted, '--haystack', $haystack);
$result1 = preg_replace("@(bit) (of) (sample)@is", "\${1}" . $replacement ."$3", $haystack);
$result2 = preg_replace("@(bit) (of) (sample)@is", "\${1}" . $replacement_quoted ."$3", $haystack);
$replacement_new1 = str_replace('$', '\$', $replacement);
$replacement_new2 = str_replace('\\', '\\\\', $replacement_new1);
$result3 = preg_replace("@(bit) (of) (sample)@is", "\${1}" . $replacement_new1 ."$3", $haystack);
$result4 = preg_replace("@(bit) (of) (sample)@is", "\${1}" . $replacement_new2 ."$3", $haystack);
var_dump('--result1 (not quoted)', $result1, '--result2 (quoted)', $result2,
'--result3 ($ escaped)', $result3, '--result4 (\ and $ escaped)', $result3);
?>
这是输出:
string(13) "--replacement"
string(17) "\HELLO WORLD$1.+-"
string(20) "--replacement_quoted"
string(22) "\\HELLO WORLD\$1\.\+\-"
string(10) "--haystack"
string(26) "...a bit of sample text..."
string(22) "--result1 (not quoted)"
string(40) "...a bit\HELLO WORLDbit.+-sample text..."
string(18) "--result2 (quoted)"
string(42) "...a bit\HELLO WORLD$1\.\+\-sample text..."
string(21) "--result3 ($ escaped)"
string(39) "...a bit\HELLO WORLD$1.+-sample text..."
string(27) "--result4 (\ and $ escaped)"
string(39) "...a bit\HELLO WORLD$1.+-sample text..."
如您所见,您无法使用 preg_quote() 取胜。如果你不调用它并且只传递未修改的字符串(result1),任何看起来像捕获令牌(上面的 $1)的东西都会被替换为 无论相应的捕获组包含什么。如果您确实调用它(result2),则捕获组没有问题,但是任何其他特殊的 PCRE 字符(例如 *)也会被转义,并且转义的字符设法继续存在于输出中。对我来说还很有趣的是,两个版本都在输出中产生了一个 \。
只有通过手动引用字符,特别是 $,才能使它起作用。这可以在 result3 和 result4 中看到。然而,继续使用 \ 的奇怪之处,为 \ 添加转义的 result3 和 result4 再次在输出中产生单个 \。在替换字符串的开头添加六个 \ 字符只会在 result1、result3 和 result4 的最终输出中生成两个 \,而其中三个用于 result2。
因此,似乎大多数问题都是通过手动转义 $ 字符来解决的。似乎 \ 字符也需要转义,但我需要再考虑一下,以弄清楚到底发生了什么。无论如何,这一切都很丑陋 - 在烦人的 \${1} 语法和必须手动转义某些字符之间,代码闻起来真的很烂而且容易出错。有什么我想念的吗?有没有干净的方法来做到这一点?
【问题讨论】:
标签: php regex preg-replace pcre