正则表达式:如果某个字符在引号内,则不匹配它

Posted

技术标签:

【中文标题】正则表达式:如果某个字符在引号内,则不匹配它【英文标题】:RegEx: Don't match a certain character if it's inside quotes 【发布时间】:2014-04-05 12:58:35 【问题描述】:

披露:我已在 SO 上多次阅读 this answer,并且我知道最好不要使用正则表达式来解析 html。这个问题只是为了拓宽我对正则表达式的了解。

假设我有这个字符串:

some text <tag link="fo>o"> other text

我想匹配整个标签,但如果我使用&lt;[^&gt;]+&gt;,它只会匹配&lt;tag link="fo&gt;

如何确保引号内的&gt; 可以被忽略。

我可以简单地编写一个带有 while 循环的解析器来执行此操作,但我想知道如何使用正则表达式。

【问题讨论】:

【参考方案1】:

如果您希望它与转义双引号一起使用,请尝试:

/&gt;(?=((?:[^"\\]|\\.)*"([^"\\]|\\.)*")*([^"\\]|\\.)*$)/g

例如:

const gtExp = />(?=((?:[^"\\]|\\.)*"([^"\\]|\\.)*")*([^"\\]|\\.)*$)/g;
const nextGtMatch = () => ((exec) => 
    return exec ? exec.index : -1;
)(gtExp.exec(xml));

如果您要解析一堆 XML,您需要设置 .lastIndex

gtExp.lastIndex = xmlIndex;
const attrEndIndex = nextGtMatch(); // the end of the tag's attributes

【讨论】:

【参考方案2】:
(<.+?>[^<]+>)|(<.+?>)

您可以创建两个正则表达式,而不是使用“|”将它们放在一起, 在这种情况下:

(<.+?>[^<]+>)   #will match  some text <tag link="fo>o"> other text
(<.+?>)         #will match  some text <tag link="foo"> other text

如果第一个大小写匹配,它不会使用第二个正则表达式,所以请确保将特殊情况放在首位。

【讨论】:

【参考方案3】:

正则表达式:

<[^>]*?(?:(?:('|")[^'"]*?\1)[^>]*?)*>

在线演示:

http://regex101.com/r/yX5xS8

完整解释:

我知道这个正则表达式可能会让人头疼,所以这是我的解释:

<                      # Open HTML tags
    [^>]*?             # Lazy Negated character class for closing HTML tag
    (?:                # Open Outside Non-Capture group
        (?:            # Open Inside Non-Capture group
            ('|")      # Capture group for quotes, backreference group 1
            [^'"]*?    # Lazy Negated character class for quotes
            \1         # Backreference 1
        )              # Close Inside Non-Capture group
        [^>]*?         # Lazy Negated character class for closing HTML tag
    )*                 # Close Outside Non-Capture group
>                      # Close HTML tags

【讨论】:

你确定[^\1] 做了你认为的事情吗?我不认为\1 可以在这样的字符类中使用。 你是对的!我真傻。我对其进行了更改,使其成为引号的否定字符类,因为无论如何这都是我们将与第 1 组匹配的全部。虽然当我们开始在双引号中包含单引号时这会带来问题......我确实有一个解决方案,但它很长。 惊人的华丽和美丽的正则表达式!谢谢! 为什么不用正则表达式?一个用于" 分隔参数,一个用于'?然后仅在第二个不匹配时尝试第二个正则表达式? 或者,就此而言,您可以使用(?:'[^']*'|"[^"]*")(而不是(?:('|")[^'"]*?\1))。 (你真的不需要引号内的*? 限定符。无论你使用* 还是*?,这里的匹配总是相同的。)【参考方案4】:

这是对 Vasili Syrakis 答案的轻微改进。它完全分别处理"…"'…',并且不使用*? 限定符。

正则表达式

&lt;[^'"&gt;]*(("[^"]*"|'[^']*')[^'"&gt;]*)*&gt;

演示

http://regex101.com/r/jO1oQ1

说明

<                    # start of HTML tag
    [^'">]*          #   any non-single, non-double quote or greater than
    (                #   outer group
        (            #     inner group
            "[^"]*"  #       "..."
        |            #      or
            '[^']*'  #       '...'
        )            #
        [^'">]*      #   any non-single, non-double quote or greater than
    )*               #   zero or more of outer group
>                    # end of HTML tag

此版本比 Vasilis 的版​​本更好,因为"…" 中允许使用单引号,'…' 中允许使用双引号,并且像 &lt;a href='&gt; 这样的(不正确的)标签将匹配。

这比 Vasili 的解决方案略,因为组被捕获了。如果您不希望这样,请在所有位置将( 替换为(?:。 (仅使用( 会使正则表达式更短,并且更具可读性)。

【讨论】:

以上是关于正则表达式:如果某个字符在引号内,则不匹配它的主要内容,如果未能解决你的问题,请参考以下文章

正则表达式 (C#):匹配 > < 或(非法 XML 字符)但仅当包含在引号内时

JS如何用正则表达式 获取字符串内的匹配部份?

正则表达式:如果条件发生则匹配值

正则表达式 - 如果模式匹配,则替换双引号之间的字符(逗号)

怎么用正则表达式匹配小括号里内容(含括号)?

正则表达式 - 获取引号中的字符串忽略转义的引号和评论