【问题标题】: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 循环的解析器来执行此操作,但我想知道如何使用正则表达式。

【问题讨论】:

    标签: regex escaping quotes


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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2015-10-28
          • 1970-01-01
          • 2018-01-15
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多