带有编号反向引用的preg_replace()中的否定回溯无效

时间:2014-07-02 05:52:58

标签: php regex preg-replace regex-lookarounds

我有一个正则表达式函数,它会接受我输入的$ text并返回相同的文本,但是看起来像远程的任何东西就像格式化为嵌入式<a href></a>的网址。

preg_replace('@(http)?(s)?(://)?(([-\w]+\.)+([^\s]+)+[^,.\s])@', '<a href="http$2://$4">$1$2$3$4</a>', $text)

示例输出:
http://www.example.com =&gt; <a href="http://www.example.com">http://www.example.com</a>
 https://www.example.com =&gt; <a href="https://www.example.com">https://www.example.com</a>
 www.example.com =&gt; <a href="http://www.example.com">www.example.com</a>

现在,我想扩展它,以便执行此操作时,遇到一个“在它前面的网络地址 - 我正试图阻止它从重新嵌入已经在href =“”属性中的地址。所以,我尝试添加负面回顾,如下所示:

preg_replace('@(?<!")(http)?(s)?(://)?(([-\w]+\.)+([^\s]+)+[^,.\s])@', '<a href="http$2://$4">$1$2$3$4</a>', $text)

不幸的是,添加回顾不仅不会阻止引擎替换双引号前面的地址上的模式,它最终也会完全破坏输出。我无法弄清楚它是不是?操作员弄乱了回顾,或者回顾周围的括号实际上是否在替换规则中抛弃了我的反馈。再一次 - 我思考他们没有贡献任何捕获的模式。

3 个答案:

答案 0 :(得分:3)

我建议这个正则表达式不需要任何锚定(因此可以在包含链接和文本的页面上使用):

<a href\s?=\s?"http(s)?://([^"]+)">([^<]+)</a>|(http)?(s)?(://)?((?:[-\w]+\.)+\S+[^,.\s])

用法:

$result = preg_replace('~<a href\s?=\s?"http(s)?://([^"]+)">([^<]+)</a>|(http)?(s)?(://)?((?:[-\w]+\.)+\S+[^,.\s])~', '<a href="http$1$5://$2$7">$3$4$5$6$7</a>', $text);

正则表达式匹配正常&#39; url和已经包含在锚标记之间的URL,但在替换中对它们的处理方式不同。

答案 1 :(得分:0)

使用以下正则表达式在<a>代码中嵌入网站地址,而不是嵌入已嵌入的网站地址。

正则表达式:

^(?!<a href.*$)(http)?(s)?(:\/\/)?(([-\w]+\.)+([^\s]+)+[^,.\s])

<强>换人:

<a href="http$2://$4">$1$2$3$4</a>

DEMO

PHP代码:

<?php
$mystring = <<<EOT
http://www.example.com
https://www.example.com
www.example.com
<a href="http://www.example.com">http://www.example.com</a>
EOT;
$pattern = "~^(?!<a href.*$)(http)?(s)?(:\/\/)?(([-\w]+\.)+([^\s]+)+[^,.\s])~m";
$replacement = '<a href="http$2://$4">$1$2$3$4</a>';
echo preg_replace($pattern, $replacement, $mystring);
?>

<强>输出:

<a href="http://www.example.com">http://www.example.com</a>
<a href="https://www.example.com">https://www.example.com</a>
<a href="http://www.example.com">www.example.com</a>
<a href="http://www.example.com">http://www.example.com</a>

答案 2 :(得分:0)

Avinash Raj和Jerry都提供了与我的问题中所述的参数和要求相匹配的解决方案,并且大大扩展了我对正则表达式的了解。不幸的是,我发现两个解决方案都开始用iframe src属性,mailto:地址(@符号后面)等替换字符串中带有句点分隔的地址。

经过多次尝试让正则表达式来弥补所有这些可能性之后,作为Jerry解决方案中第一个替代<a>标签内的地址的替代方案,我得出结论杰克,他发布了这里的第一个解决方案(并且不再存在)是正确的;我根本无法为我的用户提供协议猜测。所以我改变了要求:协议是必要的,用户必须指定http(s)或ftp(s)。这不是我的要求,但我想不出更好的解决方案。为此,I devised this (considerably simpler) regex and substitution规则如下:

<强>正则表达式:

~(?<!["'>])(http|ftp)(s)?://((?:[-\w]+\.)+\S+[^,.\s])~g

<强>换人:

<a href="$1$2://$3">$3</a>

我将此作为一个单独的答案发布,因为从技术上来说,它不会受到Avinash和Jerry所维护的参数的影响,而且这些参数构成了我的问题。问题的简单事实是,我无法找到一个解决方案,它会破坏iframe和其他我无法控制的元素。但我不能想到比要求用户为其链接包含协议更好的方法。我认为这是最合理的妥协,但如果有人有更好的解决方案,我很乐意听到它。

感谢大家对正则表达式本质的深入了解,特别感谢Avinash再次向我展示了regex101。