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 截取字符串并以零补齐str_pad() 函数
May 07 PHP
PHP类与对象中的private访问控制的疑问
Nov 01 PHP
探讨方法的重写(覆载)详解
Jun 08 PHP
PHP中判断变量为空的几种方法分享
Aug 26 PHP
thinkphp3.0输出重复两次的解决方法
Dec 19 PHP
微信自定义菜单的处理开发示例
Apr 16 PHP
WordPress中获取所使用的模板的页面ID的简单方法
Dec 31 PHP
PHP Yaf框架的简单安装使用教程(推荐)
Jun 08 PHP
php正则表达式基本知识与应用详解【经典教程】
Apr 17 PHP
Yii框架函数简单用法分析
Sep 09 PHP
php5与php7的区别点总结
Oct 11 PHP
解决laravel资源加载路径设置的问题
Oct 14 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常用技术文之文件操作和目录操作总结
2014/09/27 PHP
解决Laravel5.x的php artisan migrate数据库迁移创建操作报错SQLSTATE[42000]
2020/04/06 PHP
JS实现浏览器菜单命令
2006/09/05 Javascript
不用MOUSEMOVE也能滑动啊
2007/05/23 Javascript
JQuery下的Live方法和$.browser方法使用代码
2010/06/02 Javascript
基于mootools 1.3框架下的图片滑动效果代码
2011/04/22 Javascript
解决遍历时Array.indexOf产生的性能问题
2012/07/03 Javascript
详解Javascript模板引擎mustache.js
2016/01/20 Javascript
javascript 数组的定义和数组的长度
2016/06/07 Javascript
基于jQuery实现滚动切换效果
2016/12/02 Javascript
JS实现淡入淡出图片效果的方法分析
2016/12/20 Javascript
详解AngularJS ng-class样式切换
2017/06/27 Javascript
javascript将url解析为json格式的两种方法
2017/08/18 Javascript
详解vue.js之绑定class和style的示例代码
2017/08/24 Javascript
PHP自动加载autoload和命名空间的应用小结
2017/12/01 Javascript
vue.js 2.0实现简单分页效果
2019/07/29 Javascript
小程序角标的添加及绑定购物车数量进行实时更新的实现代码
2020/12/07 Javascript
vue 实现图片懒加载功能
2020/12/31 Vue.js
从零学Python之引用和类属性的初步理解
2014/05/15 Python
python爬虫之百度API调用方法
2017/06/11 Python
Python实现按学生年龄排序的实际问题详解
2017/08/29 Python
为什么str(float)在Python 3中比Python 2返回更多的数字
2018/10/16 Python
python实现计算器简易版
2020/12/17 Python
HTML5 移动页面自适应手机屏幕四类方法总结
2017/08/17 HTML / CSS
阿里健康官方海外旗舰店:阿里健康国际自营
2017/11/24 全球购物
马来西亚银饰品牌:JEOEL
2017/12/15 全球购物
世界顶级俱乐部的官方球衣和套装:Subside Sports
2018/04/22 全球购物
Reebok官方旗舰店:美国知名健身品牌锐步
2019/01/07 全球购物
美国排名第一的泳池用品直接来源:In The Swim
2019/09/23 全球购物
科颜氏香港官方网店:Kiehl’s香港
2021/03/07 全球购物
介绍一下write命令
2014/08/10 面试题
医药营销个人求职信范文
2014/02/07 职场文书
2015年教师党员承诺书
2015/04/27 职场文书
公司年会开场白
2015/06/01 职场文书
《称赞》教学反思
2016/02/17 职场文书
Nginx 常用配置
2022/05/15 Servers