芒果小站

  1. 全球最具业界良心的主机 - Linode

    毫无疑问,目前做得最好的主机供应商

    猛击这里查看

  2. 芒果小站目前使用的主机 - Linode

    客服响应快,随时退款,XEN 架构稳定

    猛击这里查看

  3. 最好的日本东京线路主机 - Linode

    可选弗里蒙特、达拉斯、亚特兰大、纽瓦克、伦敦、东京机房

    猛击这里查看

  • 1
  • 2
  • 3
切换到精简模式
4

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

作者 芒果/分类 代码/发布于 2012-12-14 16:45

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

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

第一种,$ 符号使用实体字符(&#36;),避免造成和 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

版权所有,转载请注明出处。
转载自 <a href="http://mangguo.org/string-replacement-preg_replace-back-reference/" title="关于字符串替换及 preg_replace 函数的后向引用" rel="bookmark">关于字符串替换及 preg_replace 函数的后向引用 | 芒果小站</a>
如果喜欢这篇文章,欢迎订阅芒果小站以获得最新内容。

已经有 4 条群众意见

  1. 听海 /2012-12-18 12:47

    目前正在学习php…没能注意到这样仔细的问题… 回应

    #1
  2. 张飞日记 /2012-12-19 21:26

    不错,学习! 回应

    #2
  3. 阿健 /2012-12-20 20:25

    没白来,有收获~呵呵~ 回应

    #3
  4. ?
    关于字符串替换及 preg_replace 函数的后向引用 | wordpress主题下载|wordpress教程|wordpress 插件| wordpress主机 /2012-12-23 00:38

    […] 2010 芒果小站 | 固定链接 | 3 条评论 | 标签 PHP, preg_replace, str_replace […] 回应

    #4

下面我简单说几句