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 正确解码javascript中通过escape编码后的字符
Jan 28 PHP
PHP 第二节 数据类型之数组
Apr 28 PHP
php警告Creating default object from empty value 问题的解决方法
Apr 02 PHP
destoon二次开发入门示例
Jun 20 PHP
php实现无限级分类
Dec 24 PHP
PHP基于文件存储实现缓存的方法
Jul 20 PHP
关于php中一些字符串总结
May 05 PHP
Smarty模板引擎缓存机制详解
May 23 PHP
PHP通过加锁实现并发情况下抢码功能
Aug 10 PHP
Laravel实现自定义错误输出内容的方法
Oct 10 PHP
php常用数组函数实例小结
Dec 29 PHP
PHP新特性详解之命名空间、性状与生成器
Jul 18 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
Email+URL的判断和自动转换函数
2006/10/09 PHP
Thinkphp模板标签if和eq的区别和比较实例分析
2015/07/01 PHP
PHP使用递归按层级查找数据的方法
2019/11/10 PHP
jQuery中的常用事件总结
2009/12/27 Javascript
window.onbeforeunload方法在IE下无法正常工作的解决办法
2010/01/23 Javascript
jQuery UI 应用不同Theme的办法
2010/09/12 Javascript
javascript奇异的arguments分析
2010/10/20 Javascript
javascript 全选与全取消功能的实现代码
2012/12/23 Javascript
一个判断抢购时间是否到达的简单的js函数
2014/06/23 Javascript
谈谈Jquery中的children find 的区别有哪些
2015/10/19 Javascript
三个js循环的关键字示例(for与while)
2016/02/16 Javascript
JavaScript数组去重的两种方法推荐
2016/04/05 Javascript
基于jquery实现表格内容筛选功能实例解析
2016/05/09 Javascript
JavaScript实现多栏目切换效果
2016/12/12 Javascript
基于ajax与msmq技术的消息推送功能实现代码
2016/12/26 Javascript
JavaScript中的工厂函数(推荐)
2017/03/08 Javascript
Vue.js在使用中的一些注意知识点
2017/04/29 Javascript
基于hover的用法实例(推荐)
2017/07/04 Javascript
javascript 开发之网页兼容各种浏览器
2017/09/28 Javascript
Angular简单验证功能示例
2017/12/22 Javascript
Vuex的初探与实战小结
2018/11/26 Javascript
基于vue-simple-uploader封装文件分片上传、秒传及断点续传的全局上传插件功能
2021/02/23 Vue.js
Python 时间处理datetime实例
2008/09/06 Python
Python文件处理
2016/02/29 Python
Python读取txt内容写入xls格式excel中的方法
2018/10/11 Python
pygame游戏之旅 添加碰撞效果的方法
2018/11/20 Python
详解在Python中以绝对路径或者相对路径导入文件的方法
2019/08/30 Python
python中id函数运行方式
2020/07/03 Python
python获取linux系统信息的三种方法
2020/10/14 Python
CSS3 实现弹幕的示例代码
2017/08/07 HTML / CSS
美国花园雕像和家居装饰网上商店:Design Toscano
2019/03/09 全球购物
French Connection官网:女装、男装及家居用品
2019/03/18 全球购物
2014年小学植树节活动方案
2014/03/02 职场文书
优秀学生干部个人事迹材料
2014/06/02 职场文书
写给医护人员的一封感谢信
2019/09/16 职场文书
SQL Server数据库的三种创建方法汇总
2023/05/08 MySQL