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之第十天
Oct 09 PHP
nginx+php-fpm配置文件的组织结构介绍
Nov 07 PHP
PHP5函数小全(分享)
Jun 06 PHP
php使用google地图应用实例
Dec 31 PHP
php截取中文字符串函数实例
Feb 23 PHP
php数组使用规则分析
Feb 27 PHP
Yii2搭建后台并实现rbac权限控制完整实例教程
Apr 28 PHP
PHP实现加密文本文件并限制特定页面的存取的效果
Oct 21 PHP
php从数据库读取数据,并以json格式返回数据的方法
Aug 21 PHP
Laravel实现ApiToken认证请求
Oct 14 PHP
Yii 框架入口脚本示例分析
May 19 PHP
PHP读取文件或采集时解决中文乱码
Mar 09 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
论建造顺序的重要性
2020/03/04 星际争霸
学习使用PHP数组
2006/10/09 PHP
PHP下常用正则表达式整理
2010/10/26 PHP
整理的9个实用的PHP库简介和下载
2010/11/09 PHP
PHP中几个常用的魔术常量
2012/02/23 PHP
PHP URL路由类实例
2013/11/12 PHP
ThinkPHP之R方法实例详解
2014/06/20 PHP
php面象对象数据库操作类实例
2014/12/02 PHP
php简单实现数组分页的方法
2016/04/30 PHP
可兼容php5与php7的cURL文件上传功能实例分析
2018/05/11 PHP
PHP基于rabbitmq操作类的生产者和消费者功能示例
2018/06/16 PHP
js利用Array.splice实现Array的insert/remove
2009/01/13 Javascript
JS获取页面input控件中所有text控件并追加样式属性
2013/02/25 Javascript
jquery中子元素和后代元素的区别示例介绍
2014/04/02 Javascript
JS动态增加删除UL节点LI及相关内容示例
2014/05/21 Javascript
js读取json的两种常用方法示例介绍
2014/10/19 Javascript
深入探秘jquery瀑布流的实现
2016/01/30 Javascript
使用postMesssage()实现跨域iframe页面间的信息传递方法
2016/03/29 Javascript
[原创]Javascript 实现广告后加载 可加载百度谷歌联盟广告
2016/05/11 Javascript
微信小程序非swiper组件实现的自定义伪3D轮播图效果示例
2018/12/11 Javascript
小程序二次贝塞尔曲线实现购物车商品曲线飞入效果
2019/01/07 Javascript
Angular 多级路由实现登录页面跳转(小白教程)
2019/11/19 Javascript
Vue动态加载图片在跨域时无法显示的问题及解决方法
2020/03/10 Javascript
python实现图片处理和特征提取详解
2017/11/13 Python
python如何发布自已pip项目的方法步骤
2018/10/09 Python
python抓取网页内容并进行语音播报的方法
2018/12/24 Python
Tensorflow中的降维函数tf.reduce_*使用总结
2020/04/20 Python
Python识别验证码的实现示例
2020/09/30 Python
CSS3实现同时执行倾斜和旋转的动画效果
2016/10/27 HTML / CSS
伦敦眼门票在线预订:London Eye
2018/05/31 全球购物
C#的几个面试问题
2016/05/22 面试题
大学生入党推荐书范文
2014/05/17 职场文书
中秋手机店促销方案
2014/06/16 职场文书
结婚保证书
2015/01/16 职场文书
汽车质检员岗位职责
2015/04/08 职场文书
实习证明格式范文
2015/06/16 职场文书