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 相关文章推荐
用Socket发送电子邮件
Oct 09 PHP
基于PHP+MySQL的聊天室设计
Oct 09 PHP
phpMyAdmin链接MySql错误 个人解决方案
Dec 28 PHP
PHP类与对象中的private访问控制的疑问
Nov 01 PHP
PHP数据类型之整数类型、浮点数的介绍
Apr 28 PHP
php获取网页请求状态程序示例
Jun 17 PHP
ThinkPHP的I方法使用详解
Jun 18 PHP
Linux下手动编译安装PHP扩展的例子分享
Jul 15 PHP
浅谈php函数serialize()与unserialize()的使用方法
Aug 19 PHP
PHP中使用数组指针函数操作数组示例
Nov 19 PHP
php打造智能化的柱状图程序,用于报表等
Jun 19 PHP
php类自动加载器实现方法
Jul 28 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用户指南-cookies部分
2006/10/09 PHP
利用PHP和AJAX创建RSS聚合器的代码
2007/03/13 PHP
Discuz 模板引擎的封装类代码
2008/07/18 PHP
PHP递归遍历指定目录的文件并统计文件数量的方法
2015/03/24 PHP
php array_chunk()函数用法与注意事项
2019/07/12 PHP
js函数使用技巧之 setTimeout(function(){},0)
2009/02/09 Javascript
javascript 去字符串空格终极版(支持utf8)
2009/11/14 Javascript
表单验证的完整应用案例探讨
2013/03/29 Javascript
解析使用JS 清空File控件的路径值
2013/07/08 Javascript
js为空或不是对象问题的快速解决方法
2013/12/11 Javascript
jquery+css3实现会动的小圆圈效果
2016/01/27 Javascript
js浏览器html5表单验证
2016/10/17 Javascript
Vue2.0 从零开始_环境搭建操作步骤
2017/06/14 Javascript
vue子父组件通信的实现代码
2017/07/09 Javascript
jQuery模拟爆炸倒计时功能实例代码
2017/08/21 jQuery
vue + vuex todolist的实现示例代码
2018/03/09 Javascript
vue加载自定义的js文件方法
2018/03/13 Javascript
Vue2.0实现简单分页及跳转效果
2019/07/29 Javascript
layui实现form表单同时提交数据和文件的代码
2019/10/25 Javascript
[01:03:47]VP vs NewBee Supermajor 胜者组 BO3 第一场 6.5
2018/06/06 DOTA
Python二维码生成库qrcode安装和使用示例
2014/12/16 Python
Python的randrange()方法使用教程
2015/05/15 Python
简单介绍Python中的decode()方法的使用
2015/05/18 Python
Python实现通讯录功能
2018/02/22 Python
python后端接收前端回传的文件方法
2019/01/02 Python
浅谈django url请求与数据库连接池的共享问题
2019/08/29 Python
python飞机大战pygame游戏背景设计详解
2019/12/17 Python
PyCharm第一次安装及使用教程
2020/01/08 Python
世界上第一个水枕头:Mediflow
2018/12/06 全球购物
Lime Crime官网:美国一家主打梦幻精灵系的彩妆品牌
2019/03/22 全球购物
实现向右循环移位
2014/07/31 面试题
应届毕业生自荐信例文
2014/02/26 职场文书
留学经费担保书
2014/05/12 职场文书
离职证明标准格式
2014/09/15 职场文书
2016自主招生教师推荐信范文
2015/03/23 职场文书
关于React Native 无法链接模拟器的问题
2021/06/21 Javascript