2

叹息,正则表达式又麻烦了。

我有以下内容$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);

关键是仅在 url 前面没有[img]or[url]且后面没有[/img]or的情况下才替换它[/url]。在上一个示例的输出中,我得到:

there was link

and

there was link

URL 和lookbehind 和lookbehind 正则表达式都可以单独工作。

$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

4 回答 4

2

假设我理解您,您希望将 $input 中的所有 URL 替换为“链接在此处”,除非 URL 位于 url 或 img bbcode 标记内。环视断言不起作用的原因是因为这些部分实际上与您非常贪婪的 URL 模式匹配(我很确定这会做很多您不想要的事情)。编写将匹配其他文本中的任何有效 URL(包括查询字符串)并且也不匹配附加到它的标签的模式不一定是最简单的事情。特别是因为您当前的模式有 http:// 或 ftp:// 作为可选。

您可能获得任何成功的唯一方法是确定一组构成 url 的严格规则。

于 2010-08-14T14:01:31.527 回答
0

很难完全理解你的问题,但看起来你正在做反向 BBcode。那么,如果它被标签包围,不要管它? 如果是这种情况,那么我认为您将遇到一个有趣的问题,因为 URL 正则表达式非常复杂。

我认为您可能使这比需要的更复杂。相反,我会更改 BBcode 之间的任何内容。这是我认为需要发生的事情:

  1. 找到字符串段“[url]”
  2. 捕获任何进行它的东西
  3. 当看到字符串段“[/url]”时结束捕获

这是一个简单的正则表达式:

$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\])#";

一个重要提示:这不会清理用户输入。确保你这样做,但我会分开逻辑,所以很容易看到你在做什么以及你在哪里做。我也会使用库来执行此操作,因为它更容易并且可能更安全。

于 2010-08-14T15:42:19.767 回答
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 开头的链接。没有找到解决此问题的其他方法。

于 2010-08-14T17:54:14.823 回答
0

我的错在哪里?

好吧,最糟糕的错误是向后看。它不是必需的,它使工作变得比需要的困难得多。假设现有标签格式正确,您无需费心寻找开始标签;结束标签的存在暗示了它的存在。

编辑:您的正则表达式除了后视之外还有其他几个问题,但尝试修复它似乎不值得。相反,我从 RegexBuddy 的内置有用正则表达式库中获取了一个正则表达式,并为其添加了前瞻。

试试这个正则表达式(或在ideone上查看它的实际效果):

'_\b(?>
     (?>www\.|ftp\.|(?:https?|ftp|file)://)  # scheme or subdomain
     [-+&@#/%=~|$?!:,.\w]*[+&@#/%=~|$\w]     # everything else
   )(?!\[/(?:img|url)\])
 _x'

仅仅因为一个问题可以用向前或向后、在前或后等方面来描述,并不意味着您应该以这种方式设计正则表达式。特别是 Lookbehind永远不应该是您使用的第一个工具。

于 2010-08-16T04:55:35.807 回答