我正在使用正则表达式将字符串中的所有电子邮件地址替换为不错的<a>
,以使其可以点击。除了在电子邮件地址前面有两个具有特定最小长度的单词和它们之间的短划线的情况之外,这种方式非常有效。只有这样我才得到一个空字符串。
<?php
$search = '#(^|[ \n\r\t])(([a-z0-9\-_]+(\.?))+@([a-z0-9\-]+(\.?))+[a-z]{2,5})#si';
$replace = '\\1<a href="mailto:\\2">\\2</a>';
$string = "tttteeee-sssstttt mail@test.nl";
echo preg_replace($search, $replace, $string);
// Output: "" (empty)
$string = "te-st mail@test.nl";
echo preg_replace($search, $replace, $string);
// Output: "te-st <a href="mailto:mail@test.nl">mail@test.nl</a>" (as expected)
$string = "mail@test.nl tttteeee-sssstttt";
echo preg_replace($search, $replace, $string);
// Output: "<a href="mailto:mail@test.nl">mail@test.nl</a> tttteeee-sssstttt" (as expected)
?>
我已经尝试了一切,但我真的找不到问题。一个解决方案是删除正则表达式中的第一个破折号(在@符号之前),但这样在@之前用破折号的电子邮件地址就不会突出显示。
答案 0 :(得分:2)
好的,最小用例:#([a-z-]+\.?)+@#
,它达到了回溯限制(使用preg_last_error()
),它无法确定放置的位置,因为\.
是可选的,决定是否使用内部或外部+
是很多工作。默认限制pcre.backtrack_limit
为100000不起作用,将其设置为1000000。
要解决此问题,请在解析器上更轻松:第一个(([a-z0-9\-_]+(\.?))+
应该变为:([a-z0-9\-_]+(\.[a-z0-9\-_]+)*)
,这在内部更容易解决。作为奖励,而不是接受的答案,这仍然不允许连续点。
答案 1 :(得分:1)
请尝试将此用作搜索字符串:
$search = '#(^|\b)([A-Z0-9_\-.]+@[A-Z0-9_\-.]+\.[A-Z]{2,5})($|\b)#i';