【问题标题】:Regex exactly n OR m times正则表达式正好 n 或 m 次
【发布时间】:2012-12-02 05:22:51
【问题描述】:

考虑以下正则表达式,其中X任何正则表达式。

X{n}|X{m}

此正则表达式将测试 X 是否发生准确 nm 次。

是否有一个正则表达式量词可以测试X 恰好nm 次的出现?

【问题讨论】:

  • 没有。对于一般mn,出现两次X 是最好的。
  • 如果这是我的问题,我会尝试正则表达式反向引用,并以(X)\1{n-1}(?:\1{m-n-1}) 开头。我知道这至少匹配X 一次,但只是开始尝试这个简单的事情,然后使用前瞻或后视而不是(X) 进行优化。

标签: java php regex


【解决方案1】:

没有一个量词表示“正好 m 或 n 次”。你这样做的方式很好。

另一种选择是:

X{m}(X{k})?

其中m < nkn-m 的值。

【讨论】:

    【解决方案2】:

    这是量词的完整列表(参考http://www.regular-expressions.info/reference.html):

    • ?, ?? - 0 或 1 次出现(?? 是懒惰的,? 是贪婪的)
    • **? - 出现次数不限
    • +, +? - 至少出现一次
    • {n} - 恰好是 n 发生次数
    • {n,m} - nm 出现次数,包括
    • {n,m}? - nm 出现,懒惰
    • {n,}, {n,}? - 至少出现n

    要获得“恰好 N 或 M”,您需要编写两次量化的正则表达式,除非 m,n 是特殊的:

    • X{n,m} 如果m = n+1
    • (?:X{n}){1,2} 如果m = 2n
    • ...

    【讨论】:

    • 为什么在 if m = 2n 示例中需要 ?:?没有它对我来说似乎工作正常。
    • @erb 如果您忽略了?:,该组将成为捕获组。除了正则表达式引擎记住它不需要的东西之外,如果你在这个之后有捕获组,它们的 ID 会改变。如果您使用正则表达式进行替换,则必须调整替换。
    【解决方案3】:

    不,没有这样的量词。但我会将其重组为/X{m}(X{m-n})?/ 以防止problems in backtracking

    【讨论】:

      【解决方案4】:

      TLDR; (?<=[^x]|^)(x{n}|x{m})(?:[^x]|$)

      看起来你想要“x n 次”或“x m 次”,我认为正则表达式的直译是 (x{n}|x{m}). 赞这个https://regex101.com/r/vH7yL5/1

      或者,如果你可以有超过 m 个“x”的序列(假设 m > n),你可以添加 'following no "x"' 和 'followed by no "x",翻译成[^x](x{n}|x{m})[^x] 但这会假设你的“x”后面和之后总是有一个字符。正如你在这里看到的:https://regex101.com/r/bB2vH2/1

      您可以将其更改为(?:[^x]|^)(x{n}|x{m})(?:[^x]|$),翻译为“没有'x'或跟随行开始”和“跟随没有'x'或跟随行结束”。但是,它仍然不会匹配两个只有一个字符的序列(因为第一个匹配需要一个字符,第二个需要一个字符),如您在此处看到的:https://regex101.com/r/oC5oJ4/1

      最后,为了匹配一个字符的远距离匹配,您可以在“no 'x' after”上添加正面向前看 (?=) 或在“no 'x' 上添加正面向后看 (?https://regex101.com/r/mC4uX3/1

      (?<=[^x]|^)(x{n}|x{m})(?:[^x]|$)
      

      这样你将只匹配你想要的“x”的确切数量。

      【讨论】:

        【解决方案5】:

        非常老的帖子,但我想贡献一些可能会有所帮助的东西。 我已经完全按照问题中所述的方式进行了尝试,它确实有效,但有一个问题: 数量的顺序很重要。考虑一下:

        #[a-f0-9]{6}|#[a-f0-9]{3}
        

        这将找到所有出现的十六进制颜色代码(它们的长度为 3 位或 6 位)。但是当我像这样翻转它时

        #[a-f0-9]{3}|#[a-f0-9]{6}
        

        它只会找到 3 位数字或 6 位数字的前 3 位数字。这确实是有道理的,Regex 专业人士可能会立即发现这一点,但对于许多人来说,这可能是一种特殊的行为。有一些高级的正则表达式功能可以避免这个陷阱,不管顺序如何,但并不是每个人都对正则表达式模式有深入了解。

        【讨论】:

          【解决方案6】:

          看看 Enhardened 的回答,他们表示他们的倒数第二个表达式不会匹配它们之间只有一个字符的序列。有一种简单的方法可以在不使用前瞻/后视的情况下解决此问题,那就是将开始/结束字符替换为边界字符。这使您可以匹配包括开始/结束在内的单词边界。因此,适当的表达应该是:

          (?:[^x]|\b)(x{n}|x{m})(?:[^x]|\b)

          如您在此处看到的:https://regex101.com/r/oC5oJ4/2

          【讨论】:

          • 酷,我不熟悉正则表达式如何处理边界。此方法的唯一问题是当您使用非标准边界时。看一看:regex101.com/r/j0nkeo/1regex101.com/r/4Ix7Dr/1
          • @Enhardened - 这是一个很好的观点,似乎是多个匹配组重叠的问题。在这种情况下,您需要使用look behind。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-03-31
          • 1970-01-01
          • 1970-01-01
          • 2012-01-26
          相关资源
          最近更新 更多