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 pcntl_fork和pcntl_fork 的用法
Apr 13 PHP
php截取utf-8中文字符串乱码的解决方法
Mar 29 PHP
PHP 开发环境配置(Zend Studio)
Apr 28 PHP
PHP数组传递是值传递而非引用传递概念纠正
Jan 31 PHP
解析curl提交GET,POST,Cookie的简单方法
Jun 29 PHP
CI框架入门示例之数据库取数据完整实现方法
Nov 05 PHP
php数组保存文本与文本反编成数组实例
Nov 13 PHP
php实现cookie加密的方法
Mar 10 PHP
PHP随机获取未被微信屏蔽的域名(微信域名检测)
Mar 19 PHP
PHP中的日期时间处理利器实例(Carbon)
Jun 09 PHP
php实现数字补零的方法总结
Sep 12 PHP
PHP实现支持CURL字符串证书传输的方法
Mar 23 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
CI(CodeIgniter)框架中的增删改查操作
2014/06/10 PHP
php使用pdo连接mssql server数据库实例
2014/12/25 PHP
Apache服务器下防止图片盗链的办法
2015/07/06 PHP
PHP中调用C/C++制作的动态链接库的教程
2016/03/10 PHP
php htmlentities()函数的定义和用法
2016/05/13 PHP
javascript英文日期(有时间)选择器
2007/05/02 Javascript
List all the Databases on a SQL Server
2007/06/21 Javascript
JQuery为textarea添加maxlength属性的代码
2010/04/07 Javascript
formValidator3.3的ajaxValidator一些异常分析
2011/07/12 Javascript
JQuery魔力之$(&quot;tagName&quot;)与selector
2012/03/05 Javascript
关于scrollLeft,scrollTop的浏览器兼容性测试
2013/03/19 Javascript
jquery交替变换颜色的三种方法 实例代码
2013/11/19 Javascript
JavaScript自定义日期格式化函数详细解析
2014/01/14 Javascript
SuperSlide标签切换、焦点图多种组合插件
2015/03/14 Javascript
JavaScript将字符串转换成字符编码列表的方法
2015/03/19 Javascript
基于BootStrap Metronic开发框架经验小结【五】Bootstrap File Input文件上传插件的用法详解
2016/05/12 Javascript
全面解析Bootstrap中transition、affix的使用方法
2016/05/30 Javascript
javascript回调函数的概念理解与用法分析
2017/05/27 Javascript
javascript 玩转Date对象(实例讲解)
2017/07/11 Javascript
浅谈关于axios和session的一些事
2017/07/13 Javascript
详解JavaScript按概率随机生成事件
2017/08/02 Javascript
vue 指定组件缓存实例详解
2018/04/01 Javascript
layui使用表格渲染获取行数据的例子
2019/09/13 Javascript
[51:34]Ti4主赛事胜者组 DK vs EG 2
2014/07/19 DOTA
python爬虫之模拟登陆csdn的实例代码
2018/05/18 Python
深入浅析Python传值与传址
2018/07/10 Python
python实现批量命名照片
2020/06/18 Python
Yves Rocher捷克官方网站:植物化妆品的创造者
2019/07/31 全球购物
Servlet面试题库
2015/07/18 面试题
办公室秘书自我鉴定
2014/01/18 职场文书
建筑工地大门标语
2014/06/18 职场文书
社区综治工作汇报
2014/10/27 职场文书
反四风问题学习心得体会
2016/01/22 职场文书
2019年怎样才能撰写出优秀的自荐信
2019/03/25 职场文书
python入门之算法学习
2021/04/22 Python
Python常用配置文件ini、json、yaml读写总结
2021/07/09 Python