排除匹配结果(pcre regex)

时间:2014-01-23 14:46:15

标签: regex match pcre

所以我有这个正则表达式(来自https://github.com/savetheinternet/Tinyboard/blob/master/inc/functions.php#L1620

((?:https?:\/\/|ftp:\/\/|irc:\/\/)[^\s<>()"]+?(?:\([^\s<>()"]*?\)[^\s<>()"]*?)*)((?:\s|<|>|"|\.|\]|!|\?|,|&#44;|&quot;)*(?:[\s<>()"]|$))

它适用于匹配链接,例如:http://stackoverflow.com/等。

问题是,如何排除这些标记匹配(主要是url ja img部分):

[url]http://stackoverflow.com/[/url]
[url=http://stackoverflow.com/]http://stackoverflow.com/[/url]
[img]http://cdn.sstatic.net/stackoverflow/img/sprites.png[/img]
[img=http://cdn.sstatic.net/stackoverflow/img/sprites.png]

2 个答案:

答案 0 :(得分:3)

要排除这个,您可以在表达式的开头添加此子模式:

(?:\[(url|img)](?>[^[]++|[(?!\/\g{-1}))*+\[\/\g{-1}]|\[(?:url|img)=[^]]*+])(*SKIP)(*FAIL)|your pattern here

这样做的目的是尝试匹配之前不需要的部分,并使用回溯控制动词(*FAIL)强制正则表达式引擎失败。 (*SKIP)动词强制正则表达式引擎在子模式失败之前不重试匹配的子字符串。

您可以找到有关这些功能的更多信息here

注意:假设您使用PHP进行此模式,您可以通过将/替换为默认分隔符~来改善这一非常长的模式,以避免全部/在模式中并使用具有Nowdoc语法的详细模式(x修饰符)。像这样你可以评论它,使它更具可读性并轻松改进模式

示例:

$pattern = <<<'EOF'
~
### skipping url and img bbcodes ###
(?:
    \[(url|img)]              # opening bbcode tag
    (?>[^[]++|[(?!/\g{-1}))*+ # possible content between tags
    \[/\g{-1}]                # closing bbcode tag
  |
    \[(?:url|img)= [^]]*+ ]   # self closing bbcode tags
)(*SKIP)(*FAIL)            # forces to fail and skip

| # OR

### a link ###
(
    (?:https?|ftp|irc)://      # protocol
    [^\s<>()"]+?
    (?:
        \( [^\s<>()"]*? \)     # part between parenthesis
        [^\s<>()"]*?
    )*
)
(
    (?:[]\s<>".!?,]|&#44;|&quot;)*
    (?:[\s<>()"]|$)
)
~x
EOF;

答案 1 :(得分:0)

您可以使用负面后瞻断言解决此问题。

(?<!pattern)

在您的情况下,您可以检查匹配链接之前是否没有]=字符。 正则表达式将确保确实没有发生这种情况:

(?<!(?:\=|\]))((?:https?:\/\/|ftp:\/\/|irc:\/\/)[^\s<>()"]+?(?:\([^\s<>()"]*?\)[^\s<>()"]*?)*)((?:\s|<|>|"|\.|\]|!|\?|,|&#44;|&quot;)*(?:[\s<>()"]|$))

请注意,在开头添加的唯一部分是(?<!(?:\=|\])),并且它与<a href=http://example.com>之类的链接不匹配,但您的问题没有指定此...所以如果提出问题这种预期的行为或使用负面看法自己解决。