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中的Class的几点个人看法
Oct 09 PHP
用php的ob_start来生成静态页面的方法分析
Mar 09 PHP
php判断文件上传类型及过滤不安全数据的方法
Dec 17 PHP
php使用iconv中文截断问题的解决方法
Feb 11 PHP
php中将一个对象保存到Session中的方法
Mar 13 PHP
PHP防止图片盗用(盗链)的方法小结
Nov 11 PHP
Ubuntu 16.04下安装PHP 7过程详解
Mar 28 PHP
php 数组元素快速去重
May 05 PHP
详解Yaf框架PHPUnit集成测试方法
Dec 27 PHP
PHP模糊查询技术实例分析【附源码下载】
Mar 07 PHP
YII框架模块化处理操作示例
Apr 26 PHP
Yii框架where查询用法实例分析
Oct 22 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中使用glob函数实现一句话删除某个目录下的所有文件
2014/07/22 PHP
PHP中两个float(浮点数)比较实例分析
2015/09/27 PHP
php实现的递归提成方案实例
2015/11/14 PHP
php经典算法集锦
2015/11/14 PHP
Zend Framework实现具有基本功能的留言本(附demo源码下载)
2016/03/22 PHP
PHP编译configure时常见错误的总结
2017/08/17 PHP
jquery的extend和fn.extend的使用说明
2011/01/09 Javascript
判断javascript的数据类型(示例代码)
2013/12/11 Javascript
innerText 使用示例
2014/01/23 Javascript
js中string转int把String类型转化成int类型
2014/08/13 Javascript
AngularJS基础知识笔记之过滤器
2015/05/10 Javascript
jquery及js实现动态加载js文件的方法
2016/01/21 Javascript
基于JavaScript实现高德地图和百度地图提取行政区边界经纬度坐标
2016/01/22 Javascript
JS实现列表的响应式排版(推荐)
2016/09/01 Javascript
原生js获取left值和top值的三种方法
2017/08/02 Javascript
微信小程序之滚动视图容器的实现方法
2017/09/26 Javascript
AngularJs点击状态值改变背景色的实例
2017/12/18 Javascript
js删除数组中的元素delete和splice的区别详解
2018/02/03 Javascript
vue + typescript + video.js实现 流媒体播放 视频监控功能
2019/07/07 Javascript
全网小程序接口请求封装实例代码
2020/11/06 Javascript
举例简单讲解Python中的数据存储模块shelve的用法
2016/03/03 Python
Tensorflow的可视化工具Tensorboard的初步使用详解
2018/02/11 Python
Python类装饰器实现方法详解
2018/12/21 Python
Python爬虫实现爬取百度百科词条功能实例
2019/04/05 Python
python内存监控工具memory_profiler和guppy的用法详解
2019/07/29 Python
Python基本语法之运算符功能与用法详解
2019/10/22 Python
TensorFlow查看输入节点和输出节点名称方式
2020/01/04 Python
检测tensorflow是否使用gpu进行计算的方式
2020/02/03 Python
香港草莓网土耳其网站:Strawberrynet TR
2017/03/02 全球购物
在线学习西班牙语、法语或其他语言:Babbel.com
2018/02/07 全球购物
马来西亚奢侈品牌购物商城:Valiram 247
2020/09/29 全球购物
中东最大的在线宠物店:Dubai Pet Food
2020/06/11 全球购物
金属材料工程个人求职的自我评价
2013/12/04 职场文书
网吧最新创业计划书范文
2014/03/27 职场文书
祝福语集锦:给百岁老人祝寿贺词
2019/11/19 职场文书
JavaScript函数柯里化
2021/11/07 Javascript