正则替换冲突
需要将一篇日志中的超链接自动转换成 A-tag,可以使用正则表达式查询URL
并替换成<a href="URL">URL</a>
;
同样的,要把图像链接自动转换成 IMG-tag,可以使用正则表达查询IMG
并替换成<img src="IMG"/>
;
但是如果希望将文章中的超链接和图片分别变成 A-tag 和 IMG-tag,能否分步执行上面两个过程?显然是不行的,因为图像链接是超链接的一个子集。如果先将URL
替换成<a href="URL">URL</a>
;再将IMG
并替换成<img src="IMG"/>
;可能会发生一部分的<a href="URL">URL</a>
变成了<a href="<img src="IMG"/>"><img src="IMG"/></a>
,出现了冲突。
如何解决这个问题呢?
这类处理大量被使用在论坛或博客中,所以我翻看了 wordpress 源码,关于如何处理 shortcode 的部分。最终我发现了解决问题的关键函数:preg_replace_callback()
:
preg_replace_callback — 执行一个正则表达式搜索并且使用一个回调进行替换
这个函数的行为除了 可以指定一个 callback 替代 replacement 进行替换 字符串的计算,其他方面等同于 preg_replace()。
http://hk1.php.net/preg_replace_callback
preg_replace_callback()
很巧妙的用回调函数解决了这个问题。实际上我们需要把一个有交集的匹配分类,但对每一个匹配只做一次替换。于是我们可以先构造这两个有交集的匹配的超集,对于超链接和图像链接而言,这个超集就是超链接。然后将这个超集匹配到的子串交给回调函数处理。在回调函数中完成分类,最终确定最后替换的结果。
这里我用 javascript 写一个简单的例子供参考,匹配URL的正则来自这里,匹配IMG的正则来自这里,代码如下:
var url = /((([A-Za-z]{3,9}:(?:\/\/)?)(?:[-;:&=\+\$,\w]+@)?[A-Za-z0-9.-]+|(?:www.|[-;:&=\+\$,\w]+@)[A-Za-z0-9.-]+)((?:\/[\+~%\/.\w-_]*)?\??(?:[-\+=&;%@.\w_]*)#?(?:[\w]*))?)/g;
var img = /(?:([^:\/?#]+):)?(?:\/\/([^\/?#]*))?([^?#]*\.(?:jpg|gif|png))(?:\?([^#]*))?(?:#(.*))?/;
var post = "这个网页 http://example.com/ 里面有一张很漂亮的图片:http://example.com/img.jpg";
var result = post.replace(url, function(str) {
if (img.test(str))
return "<img src='" + str + "'/>";
else
return "<a href='" + str + "'>" + str + "</a>";
});
运行结果 result
为:
这个网页 <a href='http://example.com/'>http://example.com/</a> 里面有一张很漂亮的图片:<img src='http://example.com/img.jpg'/>
javascript 的 String.replace() 同样允许使用回调函数来处理替换,可见回调函数很好地解决了该问题。
问题来源: 求一段正则