程序员人生 网站导航

关于字符串替换及 preg_replace 函数的后向引用

栏目:php教程时间:2014-01-11 18:39:14

在 PHP 里面替换字符串有很多种方法,str_replace 是再常见不过了,复杂一点的也可能会用到 preg_replace 方法。

这两个方法(str_replace 和 preg_replace)除了正则外,在循环替换的问题上也有一个恶心的差异。先看看各自的语法说明:

str_replace

mixed str_replace ( mixed $search , mixed $replace , mixed $subject [, int &$count ] )
preg_replace

mixed preg_replace ( mixed $pattern , mixed $replacement , mixed $subject [, int $limit = -1 [, int &$count ]] )
很明显在可选的参数列表中,preg_replace 多了个 limit 项,这个 limit 项控制了字符串替换操作的次数。

那么问题来了,现在需要实现如下一个需求,将下列代码中的两个 {module} 分别替换成不同的字符串:

<div class="layout grid-m0s5">
<div class="col-main">
<div class="main-wrap J_Region">{module}</div>
</div>
<div class="col-sub J_Region">{module}</div>
</div>
如果用 str_replace 方法,一次替换操作无法实现只替换一个 {module} 字符串。
如果用 preg_replace 方法,发现这个会造成个要命的 bug,比如下面这段代码:

<?php

$replace = '$12.34';
$subject = 'Pay {replace} for it.';
echo preg_replace('/{replace}/', $replace, $subject);

?>
输出的结果是:

Pay .34 for it.
而不是期望的:

Pay $12.34 for it.
究其原因,是因为 preg_replace 的第二参数存在后向引用的问题:

replacement中可以包含后向引用 或(php 4.0.4以上可用)$n,语法上首选后者。 每个 这样的引用将被匹配到的第n个捕获子组捕获到的文本替换。 n 可以是0-99,和$0代表完整的模式匹配文本。 捕获子组的序号计数方式为:代表捕获子组的左括号从左到右, 从1开始数。如果要在replacement 中使用反斜线,必须使用4个(“\”,译注:因为这首先是php的字符串,经过转义后,是两个,再经过 正则表达式引擎后才被认为是一个原文反斜线)。

要避免这个问题,有两个解决方案:

第一种,$ 符号使用实体字符($),避免造成和 PHP 语言的冲突。
第二种,使用 strpos 结合 substr_replace 的方法。例如:

$start = strpos($str, '{module}');
$str = substr_replace($str, 'http://www.mangguo.org', $start, sizeof('{module}'));
参考资料:
[1] http://php.net/manual/zh/function.str-replace.php
[2] http://php.net/manual/zh/function.preg-replace.php

------分隔线----------------------------
------分隔线----------------------------

最新技术推荐