当前位置: 首页 > 图文教程 > 网络编程 > PHP > PHP教程:preg_replace_callback()函数

PHP
PHP新手总结的PHP基础知识
php实现gb2312和unicode间编码转换
用php语言实现数据库连接详细代码介绍
详细解析 PHP 向 MySQL 发送数据过程
利用PHP V5开发多任务应用程序
详细讲解PHP中缓存技术的应用
php escapeshellcmd多字节编码漏洞
《PHP设计模式介绍》导言
《PHP设计模式介绍》第一章 编程惯用法
《PHP设计模式介绍》第二章 值对象模式
《PHP设计模式介绍》第三章 工厂模式
《PHP设计模式介绍》第四章 单件模式
《PHP设计模式介绍》第五章 注册模式
《PHP设计模式介绍》第六章 伪对象模式
《PHP设计模式介绍》第七章 策略模式
《PHP设计模式介绍》第八章 迭代器模式
《PHP设计模式介绍》第九章 观测模式
《PHP设计模式介绍》第十章 规范模式
《PHP设计模式介绍》第十一章 代理模式
《PHP设计模式介绍》第十二章 装饰器模式

PHP教程:preg_replace_callback()函数


出处:互联网   整理: 软晨网(RuanChen.com)   发布: 2009-09-28   浏览: 288 ::
收藏到网摘: n/a

最近碰到一个问题,要在一段HTML代码的链接中加一个参数,比如其中由一个A标签是这样的:

1
<a href="http://www.example.com/aaa.php">链接文字</a>

我就要在 aaa.php 的后面加上一个参数使其变成 aaa.php?request=xxx ,但问题是不是所有的链接都是aaa.php这样的形式,可能后面已经有了别的参数,比如 aaa.php?id=111 ,这样加的时候就需要把链接变成 aaa.php?id=111&request=xxx 。

由于要处理的是一大块HTML,所以首先想到的解决方案是正则替换,不过 preg_replace 不能做条件判断,只能做一种替换,然后我就找到了 preg_replace_callback() 这个函数,大喜,以为找到了银弹。这个东西的用法和 preg_replace() 函数几乎一样,不过它提供了一个 callback 函数,可以在替换的时候根据条件替换。在PHP手册中提供了这么一个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?php // 此文本是用于 2002 年的, // 现在想使其能用于 2003 年 $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);
  // 结果为: // April fools day is 04/01/2003 // Last christmas was 12/24/2002
?>

看了这个例子之后我以为只要把想要替换的内容替换掉就OK了,比如我只想更改捕获的第二个匹配项,只需要把 $matches[2]中的内容改一下返回就行了。然后我就写了下面的代码测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$content = '<a href="http://www.example.com/aaa.php">链接1</a><a href="http://www.example.com/aaa.php?id=111">链接2</a>';
 
$content = preg_replace_callback('/href=[\'|"](.*?)[\'|"]/', 'add_request', $content);
 
// 下面是 add_request 函数定义
 
function add_source($matches)
{ if(strpos($matches[1], '?')) { return $matches[1].'&request=xxx'; } else { return $matches[1].'?request=xxx'; }
}

不过实验之后却发现把代码替换得乱七八糟,我找了半天都没发现哪里出错了。后来仔细检查了一下才恍然大悟,我被手册上的例子误导了!!其实这个函数会替换匹配的整个内容,即 /href=[\'|"](.*?)[\'|"]/ (包括 href),而不只是 (.*?) 所捕获的东西。而手册例子中的正则是这样的:|(\d{2}/\d{2}/)(\d{4})| ,它的所有部分都是在()内的,所以替换成 $matches[1].($matches[2]+1) 自然不会有问题,但是它却让我误以为这个函数会有针对性地替换 $matches[1] 和 $matches[2]中的内容,事实上它还是替换整个正则匹配的内容,即 $matches[0]中的内容,而加上的括号只是为了我们对字符串操作方便而已!了解这一点之后,修改了代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$content = '<a href="http://www.example.com/aaa.php">链接1</a><a href="http://www.example.com/aaa.php?id=111">链接2</a>';
 
$content = preg_replace_callback('/href=[\'|"](.*?)[\'|"]/', 'add_request', $content);
 
// 下面是 add_request 函数定义
 
function add_source($matches)
{ if(strpos($matches[1], '?')) { return 'href="'.$matches[1].'&request=xxx"'; //注意,这里和下面都加上了正则里括号外的东西:href=" } else { return 'href="'.$matches[1].'?request=xxx"'; }
}

改好之后,测试正常。

一点学习笔记,记录在此。