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 远程文件管理,可以给表格排序,遍历目录,时间排序
Aug 07 PHP
php 目录遍历、删除 函数的使用介绍
Apr 28 PHP
php include和require的区别深入解析
Jun 17 PHP
codeigniter框架The URI you submitted has disallowed characters错误解决方法
May 06 PHP
PHP网页游戏学习之Xnova(ogame)源码解读(一)
Jun 23 PHP
php中get_defined_constants函数用法实例分析
May 12 PHP
教你php如何实现验证码
Jan 20 PHP
php中array_unshift()修改数组key注意事项分析
May 16 PHP
cakephp常见知识点汇总
Feb 24 PHP
php实现简单加入购物车功能
Mar 07 PHP
PHP+redis实现的限制抢购防止商品超发功能详解
Sep 19 PHP
PHP 计算两个时间段之间交集的天数示例
Oct 24 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
全国FM电台频率大全 - 5 内蒙古自治区
2020/03/11 无线电
解析关于java,php以及html的所有文件编码与乱码的处理方法汇总
2013/06/24 PHP
PHP实现的文件上传类与用法详解
2017/07/05 PHP
javascript之解决IE下不渲染的bug
2007/06/29 Javascript
javascript 45种缓动效果 非常酷
2011/06/28 Javascript
JavaScript中的作用域链和闭包
2012/06/30 Javascript
页面只能打开一次Cooike如何实现
2012/12/04 Javascript
javascript实现支持移动设备画廊
2015/08/24 Javascript
javascript闭包(Closure)用法实例简析
2015/11/30 Javascript
js计算时间差代码【包括计算,天,时,分,秒】
2016/04/26 Javascript
jQuery解决$符号命名冲突
2016/06/18 Javascript
Bootstrap表格使用方法详解
2017/02/17 Javascript
jQuery输入框密码的显示隐藏【代码分享】
2017/04/29 jQuery
基于JavaScript实现淘宝商品广告效果
2017/08/10 Javascript
使用JS实现图片轮播的实例(前后首尾相接)
2017/09/21 Javascript
ES6的解构赋值实例详解
2019/05/06 Javascript
解决vue页面渲染但dom没渲染的操作
2020/07/27 Javascript
python实现的守护进程(Daemon)用法实例
2015/06/02 Python
Python正则简单实例分析
2017/03/21 Python
Python实现计算两个时间之间相差天数的方法
2017/05/10 Python
Tensorflow 同时载入多个模型的实例讲解
2018/07/27 Python
给Python学习者的文件读写指南(含基础与进阶)
2020/01/29 Python
Python字符编码转码之GBK,UTF8互转
2020/02/09 Python
CSS实现限制字数功能当对象内文本溢出时显示省略标记
2014/08/20 HTML / CSS
DHC中国官方购物网站:日本通信销售No.1化妆品
2016/08/20 全球购物
马来西亚在线购物:POPLOOK.com
2019/12/09 全球购物
伊莱克斯阿根廷网上商店:Tienda Electrolux
2021/03/08 全球购物
城市创卫标语
2014/06/17 职场文书
社区党员志愿服务活动方案
2014/08/18 职场文书
教师党的群众路线教育实践活动学习笔记
2014/11/05 职场文书
旷课检讨书范文
2015/01/27 职场文书
故宫英文导游词
2015/01/31 职场文书
校长一岗双责责任书
2015/05/09 职场文书
高中生军训感言
2015/08/01 职场文书
只需要这一行代码就能让python计算速度提高十倍
2021/05/24 Python
MySQL配置主从服务器(一主多从)
2021/08/07 MySQL