叹息,正则表达式再次出现问题。
我在$text
中有以下内容:
[img]http://www.site.com/logo.jpg[/img]
and
[url]http://www.site.com[/url]
我有正则表达式:
$text = preg_replace("/(?<!(\[img\]|\[url\]))([http|ftp]+:\/\/)?\S+[^\s.,>)\];'\"!?]\.+[com|ru|net|ua|biz|org]+\/?[^<>\n\r ]+[A-Za-z0-9](?!(\[\/img\]|\[\/url\]))/","there was link",$text);
关键是只有在[img]
或[url]
之后没有[/img]
或[/url]
之后才更换网址。在上一个例子的输出中,我得到:
there was link
and
there was link
URL和lookbehind以及前瞻性的regexp都可以单独运行。
$text = "[img]bash.org/logo.jpg[/img]";
$text = preg_replace("/(?<!(\[img\]|\[url\]))bash.org(?!(\[\/img\]|\[\/url\]))/","there was link",$text);
echo $text leaves everything as is and gives me [img]bash.org/logo.jpg[/img]
我认为问题在于结合了外观和URL正则表达式。哪里是我的错?
我想
将http://www.google.com替换为“有链接”,但保持原样“[url] http://www.google.com[/url]”
我正在
http://www.google.com替换为“有链接”,[url] http://www.google.com[/url]替换为“有链接”
这里的PHP代码要测试
<?php
$text = "[url]http://www.google.com[/url] <br><br> http://www.google.com";
// should NOT be changed //should be changed
$text = preg_replace("/(?<!\[url\])([http|ftp]+:\/\/)?\S+[^\s.,>)\];'\"!?]\.+[com|ru|net|ua|biz|org]+\/?[^<>\n\r ]+[A-Za-z0-9](?!\[\/url\])/","there was link",$text);
echo $text;
echo '<hr width="100%">';
$text = ":) :-) 0:) 0:-) :)) :-))";
$text = preg_replace("/(?<!0):-?\)(?!\))/","smiley",$text);
echo $text; // lookarounds work
echo '<hr width="100%">';
$text = "http://stackoverflow.com/questions/2482921/regexp-exclusion";
$text = preg_replace("/([http|ftp]+:\/\/)?\S+[^\s.,>)\];'\"!?]\.+[com|ru|net|ua|biz|org]+\/?[^<>\n\r ]+[A-Za-z0-9]/","it's a link to stackoverflow",$text);
echo $text; // URL pattern works fine
?>
答案 0 :(得分:2)
假设我理解您,您希望替换$ input中的所有网址,并使用“link is here”字样,除非该网址位于url或img bbcode标记内。外观断言不起作用的原因是因为这些部分实际上与你非常贪婪的URL模式相匹配(我很确定你做的很多事情并不意味着它)。编写一个与其他文本中的任何有效URL(包括查询字符串)匹配的模式,以及与附加到它的标记不匹配的模式不一定是最简单的事情。特别是因为您当前的模式具有http://或ftp://作为可选项。
您可能取得任何成功的唯一方法是决定构成网址的严格规则。
答案 1 :(得分:0)
很难完全理解你的问题,但看起来你正在做反向BBcode。那么,如果它被标签包围就不管它了吗?如果是这样的话,那么我认为你手上会遇到一个有趣的问题,因为URL regex是非常复杂的。
我认为你可能会使它变得比它需要的更复杂。相反,我会改变BBcode之间的任何东西。以下是我认为需要发生的事情:
这是一个简单的正则表达式:
$string = "[url]http://www.google.com[/url] <br><br> http://www.google.com";
$replace = "there was link";
$text = preg_replace_all($regex,$replace,$text);
echo $text;
我知道这并不是你要求的(事实上,可能恰恰相反),但它会达到相同的结果并且更容易。
你可以尝试使用这个正则表达式的负向前瞻,但我不确定它会给你正确的结果:
$regex = "#(?!\[url\])(.*)(?!\[/url\])#";
一个重要说明:这不会消除用户输入。确保你这样做,但我会将逻辑分开,这样很容易看出你在做什么以及你在做什么。我也会用一个库来做这件事,因为它更容易,也可能更安全。
答案 2 :(得分:0)
最终工作正则表达式如下:
(?<!\[img\]|\[url\])((^|\s)([\w-]+://|www[.])[^\s()<>]+(?:\([\w\d]+\)|([^[:punct:]\s]|/)))(?!\[\/img\]|\[/url\])
示例:
<?php
$text = "
[img]http://google.com/logo.jpg[/img]
[img]www.google.com/logo.jpg[/img]
[img]http://www.google.com/logo.jpg[/img]
[url]http://google.com/logo.jpg[/url]
[url]www.google.com/logo.jpg[/url]
[url]http://www.google.com/logo.jpg[/url]
www.google.com/logo.jpg
http://google.com/logo.jpg
http://www.google.com/logo.jpg
";
$text = nl2br($text);
$text = preg_replace("'(?<!\[img\]|\[url\])((^|\s)([\w-]+://|www[.])[^\s()<>]+(?:\([\w\d]+\)|([^[:punct:]\s]|/)))(?!\[\/img\]|\[/url\])'i","<font color=\"#ff0000\">link</font>",$text);
echo $text;
?>
输出:
[img]http://google.com/logo.jpg[/img]
[img]www.google.com/logo.jpg[/img]
[img]http://www.google.com/logo.jpg[/img]
[url]http://google.com/logo.jpg[/url]
[url]www.google.com/logo.jpg[/url]
[url]http://www.google.com/logo.jpg[/url]
link
link
link
诀窍是只替换以^或\ s开头的链接。没有找到解决这个问题的其他方法。
答案 3 :(得分:0)
我的错误在哪里?
嗯,最糟糕的错误就是后视。它不是必需的,它使得工作变得比它需要的更难。假设现有标签格式正确,您无需费心寻找开头标签;结束标记的存在暗示了它的存在。
编辑:除了lookbehind之外,你的正则表达式还有其他几个问题,但尝试修复它似乎并不值得。相反,我从RegexBuddy的内置有用正则表达式库中获取了一个正则表达式,并为它添加了前瞻。尝试使用此正则表达式(或在ideone上查看它):
'_\b(?>
(?>www\.|ftp\.|(?:https?|ftp|file)://) # scheme or subdomain
[-+&@#/%=~|$?!:,.\w]*[+&@#/%=~|$\w] # everything else
)(?!\[/(?:img|url)\])
_x'
仅仅因为在前瞻性或后退性,前瞻性或后续性等方面可以描述问题,并不意味着您应该以这种方式设计正则表达式。 Lookbehind尤其应该永远不会成为您达到的第一个工具。