PHP正则替换函数preg_replace和preg_replace_callback使用总结


Posted in PHP onSeptember 22, 2014

在编写PHP模板引擎工具类时,以前常用的一个正则替换函数为 preg_replace(),加上正则修饰符 /e,就能够执行强大的回调函数,实现模板引擎编译(其实就是字符串替换)。

详情介绍参考博文:PHP函数preg_replace() 正则替换所有符合条件的字符串

应用举例如下:

<?php

/**

 * 模板解析类

 */

class Template {
 public function compile($template) {
  // if逻辑

  $template = preg_replace("/\<\!\-\-\{if\s+(.+?)\}\-\-\>/e", "\$this->ifTag('\\1')", $template);
  return $template;

 }
 /**

  * if 标签

  */

 protected function ifTag($str) {
  //$str = stripslashes($str); // 去反转义
  return '<?php if (' . $str . ') { ?>';

 }

}
$template = 'xxx<!--{if $user[\'userName\']}-->yyy<!--{if $user["password"]}-->zzz';
$tplComplier = new Template();
$template = $tplComplier->compile($template);
echo $template;
?>

输出结果为:

xxx<?php if ($user['userName']) { ?>yyy<?php if ($user[\"password\"]) { ?>zzz

仔细观察,发现 $user["password"] 中的双引号被转义了,这不是我们想要的结果。

为了能够正常输出,还必须反转义一下,但是,如果字符串中本身含有反转义双引号的话,我们此时反转义,原本的反转义就变成了非反转义了,这个结果又不是我们想要的,所以说这个函数在这方面用的不爽!

后来,发现一个更专业级的 正则替换回调函数 preg_replace_callback()。

mixed preg_replace_callback ( mixed pattern, callback callback, mixed subject [, int limit] )

本函数的行为几乎和 preg_replace() 一样,除了不是提供一个 replacement 参数,而是指定一个 callback 函数。该函数将以目标字符串中的匹配数组作为输入参数,并返回用于替换的字符串。

回调函数 callback:

一个回调函数,在每次需要替换时调用,调用时函数得到的参数是从subject 中匹配到的结果。回调函数返回真正参与替换的字符串。这是该回调函数的签名:

string handler ( array $matches )

像上面所看到的,回调函数通常只有一个参数,且是数组类型。

罗列一些有关preg_replace_callback()函数的实例:

Example #1 preg_replace_callback() 和 匿名函数

<?php

/* 一个unix样式的命令行过滤器,用于将段落开始部分的大写字母转换为小写。 */

$fp = fopen("php://stdin", "r") or die("can't read stdin");

while (!feof($fp)) {

    $line = fgets($fp);

    $line = preg_replace_callback(

        '|<p>\s*\w|',

        function ($matches) {

            return strtolower($matches[0]);

        },

        $line

    );

    echo $line;

}

fclose($fp);

?>

如果回调函数是个匿名函数,在PHP5.3中,通过关键字use,支持给匿名函数传多个参数,如下所示:

<?php 

$string = "Some numbers: one: 1; two: 2; three: 3 end"; 

$ten = 10; 

$newstring = preg_replace_callback( 

    '/(\\d+)/', 

    function($match) use ($ten) { return (($match[0] + $ten)); }, 

    $string 

    ); 

echo $newstring; 

#prints "Some numbers: one: 11; two: 12; three: 13 end"; 

?>

Example #2 preg_replace_callback() 和 一般函数

<?php

// 将文本中的年份增加一年.

$text = "April fools day is 04/01/2002\n";

$text.= "Last christmas was 12/24/2001\n";

// 回调函数

function next_year($matches) {

  // 通常: $matches[0]是完成的匹配

  // $matches[1]是第一个捕获子组的匹配

  // 以此类推

  return $matches[1].($matches[2]+1);

}

echo preg_replace_callback(

            "|(\d{2}/\d{2}/)(\d{4})|",

            "next_year",

            $text);
?>

Example #3 preg_replace_callback() 和 类方法

如何在类的内部调用非静态函数?你可以按如下操作:
对于 PHP 5.2,第二个参数 像这样 array($this, 'replace') :

<?php

class test_preg_callback{
  private function process($text){

    $reg = "/\{([0-9a-zA-Z\- ]+)\:([0-9a-zA-Z\- ]+):?\}/";

    return preg_replace_callback($reg, array($this, 'replace'), $text);

  }

  

  private function replace($matches){

    if (method_exists($this, $matches[1])){

      return @$this->$matches[1]($matches[2]);     

    }

  }  

}

?>

对于 PHP5.3,第二个参数像这样 "self::replace" :
注意,也可以是 array($this, 'replace')。

<?php

class test_preg_callback{
  private function process($text){

    $reg = "/\{([0-9a-zA-Z\- ]+)\:([0-9a-zA-Z\- ]+):?\}/";

    return preg_replace_callback($reg, "self::replace", $text);

  }

  

  private function replace($matches){

    if (method_exists($this, $matches[1])){

      return @$this->$matches[1]($matches[2]);     

    }

  }  

}

?>

根据上面所学到的知识点,把模板引擎类改造如下:

<?php

/**

 * 模板解析类

 */

class Template {
 public function compile($template) {
  // if逻辑

  $template = preg_replace_callback("/\<\!\-\-\{if\s+(.+?)\}\-\-\>/", array($this, 'ifTag'), $template);
  return $template;

 }
 /**

  * if 标签

  */

 protected function ifTag($matches) {

  return '<?php if (' . $matches[1] . ') { ?>';

 }

}
$template = 'xxx<!--{if $user[\'userName\']}-->yyy<!--{if $user["password"]}-->zzz';
$tplComplier = new Template();
$template = $tplComplier->compile($template);
echo $template;
?>

输出结果为:

xxx<?php if ($user['userName']) { ?>yyy<?php if ($user["password"]) { ?>zzz

正是我们想要的结果,双引号没有被反转义!

PS:关于正则,本站还提供了2款非常简便实用的正则表达式工具供大家使用:

JavaScript正则表达式在线测试工具:
http://tools.3water.com/regex/javascript

正则表达式在线生成工具:
http://tools.3water.com/regex/create_reg

PHP 相关文章推荐
PHP代码优化的53个细节
Mar 03 PHP
CodeIgniter中实现泛域名解析
Jul 19 PHP
getimagesize获取图片尺寸实例
Nov 15 PHP
PHP访问Google Search API的方法
Mar 05 PHP
详解PHP错误日志的获取方法
Jul 20 PHP
浅析PHP中Session可能会引起并发问题
Jul 23 PHP
如何使用Gitblog和Markdown建自己的博客
Jul 31 PHP
详解配置 Apache 服务器支持 PHP 文件的解析
Feb 15 PHP
Windows下php+mysql5.7配置教程
May 16 PHP
基于php流程控制语句和循环控制语句(讲解)
Oct 23 PHP
PHP设计模式之工厂方法设计模式实例分析
Apr 25 PHP
PHP时间类完整代码实例
Feb 26 PHP
php分页函数完整实例代码
Sep 22 #PHP
php中file_get_content 和curl以及fopen 效率分析
Sep 19 #PHP
PHP return语句另类用法不止是在函数中
Sep 17 #PHP
php使用$_POST或$_SESSION[]向js函数传参
Sep 16 #PHP
PHP正则表达式替换站点关键字链接后空白的解决方法
Sep 16 #PHP
一个php生成16位随机数的代码(两种方法)
Sep 16 #PHP
php数组中删除元素之重新索引的方法
Sep 16 #PHP
You might like
php环境套包 dedeampz 伪静态设置示例
2014/03/26 PHP
PHP中的流(streams)浅析
2015/07/02 PHP
PHP+Session防止表单重复提交的解决方法
2018/04/09 PHP
php设计模式之职责链模式实例分析【星际争霸游戏案例】
2020/03/27 PHP
My Desktop :) 桌面式代码
2008/12/29 Javascript
浅谈Javascript Base64 加密解密
2014/12/28 Javascript
jQuery实现多级联动下拉列表查询框
2016/01/18 Javascript
JS实现放大、缩小及拖拽图片的方法【可兼容IE、火狐】
2016/08/23 Javascript
vue从使用到源码实现教程详解
2016/09/19 Javascript
微信小程序tabbar不显示解决办法
2017/06/08 Javascript
Node.js学习之地址解析模块URL的使用详解
2017/09/28 Javascript
Easyui 去除jquery-easui tab页div自带滚动条的方法
2019/05/10 jQuery
JS为什么说async/await是generator的语法糖详解
2019/07/11 Javascript
vue.js中使用微信扫一扫解决invalid signature问题(完美解决)
2020/04/11 Javascript
解决vue刷新页面以后丢失store的数据问题
2020/08/11 Javascript
Vue 3.0中jsx语法的使用
2020/11/13 Javascript
Python实现的一个简单LRU cache
2014/09/26 Python
Python实现Windows上气泡提醒效果的方法
2015/06/03 Python
Python利用Beautiful Soup模块创建对象详解
2017/03/27 Python
Python利用operator模块实现对象的多级排序详解
2017/05/09 Python
python: line=f.readlines()消除line中\n的方法
2018/03/19 Python
Python函数式编程指南:对生成器全面讲解
2019/11/19 Python
python如何通过twisted搭建socket服务
2020/02/03 Python
xadmin使用formfield_for_dbfield函数过滤下拉表单实例
2020/04/07 Python
python def 定义函数,调用函数方式
2020/06/02 Python
Lentiamo丹麦:购买便宜的隐形眼镜
2021/01/13 全球购物
电脑销售顾问自荐信
2014/01/29 职场文书
广告业务员岗位职责
2014/02/06 职场文书
初二学习计划书范文
2014/04/27 职场文书
党员四风自我剖析材料
2014/10/07 职场文书
上诉答辩状范文
2015/05/22 职场文书
2015年幼师个人工作总结
2015/10/15 职场文书
css背景和边框标签实例详解
2021/05/21 HTML / CSS
教你如何用Python实现人脸识别(含源代码)
2021/06/23 Python
Mysql binlog日志文件过大的解决
2021/10/05 MySQL
灵能百分百第三季什么时候来?
2022/03/15 日漫