URL正则表达式除外

时间:2010-08-14 12:52:51

标签: regex url bbcode

叹息,正则表达式再次出现问题。

我在$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

?>

4 个答案:

答案 0 :(得分:2)

假设我理解您,您希望替换$ input中的所有网址,并使用“link is here”字样,除非该网址位于url或img bbcode标记内。外观断言不起作用的原因是因为这些部分实际上与你非常贪婪的URL模式相匹配(我很确定你做的很多事情并不意味着它)。编写一个与其他文本中的任何有效URL(包括查询字符串)匹配的模式,以及与附加到它的标记不匹配的模式不一定是最简单的事情。特别是因为您当前的模式具有http://或ftp://作为可选项。

您可能取得任何成功的唯一方法是决定构成网址的严格规则。

答案 1 :(得分:0)

很难完全理解你的问题,但看起来你正在做反向BBcode。那么,如果它被标签包围就不管它了吗?如果是这样的话,那么我认为你手上会遇到一个有趣的问题,因为URL regex是非常复杂的。

我认为你可能会使它变得比它需要的更复杂。相反,我会改变BBcode之间的任何东西。以下是我认为需要发生的事情:

  1. 找到字符串段“[url]”
  2. 抓住任何进展的东西
  3. 在看到字符串段“[/ url]”时结束捕获
  4. 这是一个简单的正则表达式:

    $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尤其应该永远不会成为您达到的第一个工具。