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 相关文章推荐
phpmyadmin中配置文件现在需要绝密的短语密码的解决方法
Feb 11 PHP
The specified CGI application misbehaved by not returning a complete set of HTTP headers
Mar 31 PHP
PHP按行读取、处理较大CSV文件的代码实例
Apr 09 PHP
PHP实现文件下载详解
Nov 27 PHP
php实现短信发送代码
Jul 05 PHP
PHP的Socket网络编程入门指引
Aug 11 PHP
使用phpexcel类实现excel导入mysql数据库功能(实例代码)
May 12 PHP
PHP对象、模式与实践之高级特性分析
Dec 08 PHP
Laravel 在views中加载公共页面的实现代码
Oct 22 PHP
php pdo连接数据库操作示例
Nov 18 PHP
laravel框架创建授权策略实例分析
Nov 22 PHP
Laravel配合jwt使用的方法实例
Oct 25 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基于str_pad实现卡号不足位数自动补0的方法
2014/11/12 PHP
php防止网站被刷新的方法汇总
2014/12/01 PHP
PHP的几个常用加密函数
2016/02/03 PHP
使用PHPExcel实现数据批量导出为excel表格的方法(必看)
2017/06/09 PHP
ThinkPHP删除栏目(实现批量删除栏目)
2017/06/21 PHP
PHP SFTP实现上传下载功能
2017/07/26 PHP
PHP设计模式(八)装饰器模式Decorator实例详解【结构型】
2020/05/02 PHP
PHP设计模式(九)外观模式Facade实例详解【结构型】
2020/05/02 PHP
List the Codec Files on a Computer
2007/06/18 Javascript
基于jquery的finkyUI插件与Ajax实现页面数据加载功能
2010/12/03 Javascript
dreamweaver 安装Jquery智能提示
2011/04/02 Javascript
基于jquery的$.ajax async使用
2011/10/19 Javascript
jquery为页面增加快捷键示例
2014/01/31 Javascript
vue将对象新增的属性添加到检测序列的方法
2018/02/24 Javascript
jQuery实现表单动态加减、ajax表单提交功能
2018/06/08 jQuery
jQuery实现为动态添加的元素绑定事件实例分析
2018/09/07 jQuery
vue使用v-for实现hover点击效果
2018/09/29 Javascript
详解Vue.directive 自定义指令
2019/03/27 Javascript
说说Vuex的getters属性的具体用法
2019/04/15 Javascript
小程序实现左滑删除效果
2019/07/25 Javascript
Python+Django在windows下的开发环境配置图解
2009/11/11 Python
使用C语言扩展Python程序的简单入门指引
2015/04/14 Python
浅谈Python浅拷贝、深拷贝及引用机制
2016/12/15 Python
Python多线程经典问题之乘客做公交车算法实例
2017/03/22 Python
关于python2 csv写入空白行的问题
2018/06/22 Python
利用pyshp包给shapefile文件添加字段的实例
2019/12/06 Python
详解html2canvas截图不能截取圆角图片的解决方案
2018/01/30 HTML / CSS
芭比波朗加拿大官方网站:Bobbi Brown Cosmetics CA
2020/11/05 全球购物
编辑找工作求职信分享
2014/01/03 职场文书
大学军训感言800字
2014/02/27 职场文书
幼儿园父亲节活动方案
2014/03/11 职场文书
本科毕业生应聘自荐信范文
2014/06/26 职场文书
公司试用期员工自我评价
2014/09/17 职场文书
留学推荐信英文范文
2015/03/26 职场文书
计划生育工作总结2015
2015/04/03 职场文书
《狼牙山五壮士》教学反思
2016/02/17 职场文书