【问题标题】:Match if there is a X in the first and X the second Y can be 0如果第一个有 X 并且 X 第二个 Y 可以为 0,则匹配
【发布时间】:2014-10-27 09:16:01
【问题描述】:

我目前正在开发一个程序。我需要一个接受 Y 和 X 的正则表达式,并且 X 对由 Y 分隔。它不必是相等的数字,但它不能包含多个 X 并排在一起。

例子:

# Don't match:
XXXYYYYY
#Match:
XYXYYYY
X

到目前为止我的尝试:

{Y*[X|^X]Y*[X|^X]Y*}*

问题是,如果第一个有 X,第二个有 X,那么 Y 仍然可以为 0。我可以直接测试双 X 吗?

【问题讨论】:

  • @almasshaikh 已更新问题
  • 为什么不直接测试XX并在找到时拒绝?
  • @Unihedron 这不是重点,让你对此做出反应,抱歉,但我需要的只是一些理论,我也许可以测试双 X 或类似的东西
  • 您在寻找什么样的 RE? perl 样式正则表达式,或awk 样式ERE,或sed 使用的普通RE?

标签: regex


【解决方案1】:

由于上面的答案使用前瞻,这个答案提出了一个普通正则表达式的解决方案:

^(X?Y)*X?$

上述解决方案假定允许使用空字符串。否则:

^((X?Y)+X?|X)$

(随意使组不捕获)

感谢 Unihedron 将 XY|Y 简化为 X?Y


如果有人对此答案的有效性仍有疑问,solve the below equations:

R1 = XR2 + YR3 + λ
R2 =       YR3 + λ
R3 = XR2 + YR3 + λ

DFA 可以从上面的等式中得出。

如果不允许使用空字符串,请删除 R1 中的 + λ

【讨论】:

  • 经过一些逻辑归纳,您将拥有最有效的^(X?Y)*X?$。干得好!
【解决方案2】:

它有什么不寻常的

^(?:X(?!X)|Y)+$

DEMO

解释:它只是一系列 X 和 Y,其中一个 X 后面不能跟着另一个 X(负前瞻)。

【讨论】:

  • 由于Y 在逻辑上看起来等于或大于Xs 的数量,因此将交替更改为在前面包含Y 可能会使匹配输入的效率稍高一些.
  • @Unihedron 你甚至可以做得更好:^(?:Y++|X(?!X))+$^(?:(?>Y+)|X(?!X))+$ 但由于 OP 没有指定正则表达式风格,所以我忽略了优化。
  • 有见地的评论和好点子!但是需要注意的是,在 PCRE 中 Y++ 定义为与 (?>Y+) 相同。
  • 是的,但是例如,所有格量词修饰符 (++) 在 .NET 中不可用,因此您必须使用原子组 ((?>...))...再次,一切都取决于味道:)
【解决方案3】:
^(?!.*?XX)X[YX]*$

试试这个。这应该满足您的要求。查看演示。

http://regex101.com/r/sU3fA2/8

【讨论】:

    【解决方案4】:

    你可以使用这个模式:

    ^Y*(XY+)*X?$
    

    如果要确保至少有一个字符,可以单独检查长度或在开头添加一个lookahead:

    ^(?=.)Y*(?:XY+)*X?$
    

    关于灾难性的回溯:

    如果您使用 DFA 正则表达式引擎,则没有问题,因为没有回溯。

    如果您使用 NFA 正则表达式引擎,您可以通过多种方式防止灾难性的回溯,例如:

    ^Y*(XY|Y)*X?$       # possible but not really efficient
    
    ^Y*(?>XY+)*X?$      # using an atomic group (if available)
    
    ^Y*(?:XY+)*+X?$     # using a possessive quantifier (if available)
    
    ^Y*(?=((XY+)*))\1X?$ # emulate `(?>(?:XY+)*)`
    
    ^Y*(?:(?=(XY+))\1)*X?$  # emulate `(?>XY+)*`
    

    【讨论】:

    • 有趣的理论,但为了不让用户的代码因灾难性回溯而烧毁,最好在语言支持的地方使用(?> ) 而不是(?: ) :)
    • ^Y*(XY|Y)*X?$ 删除第一个Y*(因为Y* 已经包含在(XY|Y)* 中,并且解决方案将与我的相同。其余的都是多余的,因为^(XY|Y)*X?$ 将永远不会有回溯问题。
    • @nhahtdh: ^Y*(XY|Y)*X?$ 确实可以缩短为^(X?Y)*X?$。然而,这种模式效率较低,因为失败前的步骤数是使用原子分组的模式的 4 倍。所以它们根本不是多余的。因此,通过单面体简化,最有效的模式是^(?>X?Y+)*+X?$
    • @CasimiretHippolyte:我无法观察到 4 倍的差异。但是,如果我使用^(X?Y)*+X?$,我确实看到了 2 倍的差异。当使用所有格量词时,(?> 是不必要的。无论如何,它仍然是线性的。
    • @nhahtdh:您会更好地看到这些链接的 4 倍差异:regex101.com/r/tN7cN9/1regex101.com/r/yZ5jX7/1。确实,^(?:X?Y+)*+X?$ 就足够了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多