【问题标题】:Regular Expressions with repeated characters带有重复字符的正则表达式
【发布时间】:2012-11-20 12:23:26
【问题描述】:

我需要编写一个正则表达式,它可以检测一个只包含字符 x、y 和 z 的字符串,但其中的字符与相邻字符不同。

这是一个例子

xyzxzyz = 通过

xyxyxyx = 通过

xxyzxz = 失败(重复 x)

zzzxxzz = 失败(相邻字符重复)

我认为这会起作用 ((x|y|z)?)*,但它似乎不起作用。有什么建议吗?

编辑

请注意,我正在寻找一个不允许向前看或向后看操作的答案。唯一允许的操作是交替、连接、分组和闭包

【问题讨论】:

  • 为什么((x|y|z)?)* 不起作用?你想让它做什么不做什么?你不能只说“它不起作用”。
  • 如果这是计算机科学类的问题,要求您为语法编写正则表达式,那么您应该说明正则表达式只能由交替、连接、分组和闭合组成的要求( *),因为在实际使用中正则表达式有更多的语法,允许一个简单的解决方案。
  • @AndyLester:显然可以匹配重复字符的字符串。
  • @nhahtdh 这是一个计算机科学问题,只允许上述操作。如果它是真正的语法,我会很好地使用许多在线提供示例的资源来执行此操作,但是如果不向前看和向后看操作,我无法真正想到任何可以做到的事情
  • @MZimmerman6:你应该编辑你的问题以反映这一事实——人们只会假设你可以使用任何你想要的东西。

标签: regex computer-science


【解决方案1】:

通常对于这类问题,如果正则表达式不够简单,无法直接推导出来,可以从画一个DFA开始,从那里推导出一个正则表达式。

您应该能够推导出以下 DFA。 q1、q2、q3、q4 是结束状态,q1 也是开始状态。 q5 是失败/陷阱状态。

有多种方法可以找到 DFA 的正则表达式。我将使用 Brzozowski 代数方法,如this paper 的第 5 节所述:

对于每个状态 qi,方程 Ri 是项的并集:对于从 qi 到 qj 的转移 a,项是 aRj。基本上,您将查看一个状态的所有传出边。如果 Ri 是最终状态,则 λ 也是项之一。

让我引用论文定义部分的身份,因为它们稍后会派上用场(λ是空字符串,∅是空集):

(ab)c = a(bc) = abc
λx = xλ = x
∅x = x∅ = ∅
∅ + x = x
λ + x* = x*
(λ + x)* = x*

由于 q5 是陷阱状态,因此公式最终会无限递归,因此您可以将其放入方程式中。如果您将其包含在等式中,它将最终成为空集并消失(在附录中解释)。

你会想出:

R1 = xR2 + yR3 + zR4 + λ
R2 =     + yR3 + zR4 + λ
R3 = xR2 +     + zR4 + λ
R4 = xR2 + yR3       + λ

用代入法和 Arden 定理求解上面的方程,它指出:

给定X = AX + B 形式的方程,其中 λ ∉ A,方程有解X = A*B

你会得到答案。

我没有时间和信心推导整个事情,但我会展示推导的前几个步骤。

通过替换去掉R4,注意zλ由于恒等变成z:

R1 = xR2 + yR3 + (zxR2 + zyR3 + z) + λ
R2 =     + yR3 + (zxR2 + zyR3 + z) + λ
R3 = xR2 +     + (zxR2 + zyR3 + z) + λ

重新组合:

R1 = (x + zx)R2 + (y + zy)R3 + z + λ
R2 =       zxR2 + (y + zy)R3 + z + λ
R3 = (x + zx)R2 +       zyR3 + z + λ

将 Arden 定理应用于 R3:

R3 = (zy)*((x + zx)R2 + z + λ)
   = (zy)*(x + zx)R2 + (zy)*z + (zy)*

您可以将 R3 替换回 R2 和 R1 并删除 R3。我把剩下的留作练习。继续前进,您应该会找到答案。

附录

我们将解释为什么可以从方程中丢弃陷阱状态,因为它们无论如何都会消失。这里以 DFA 中的状态 q5 为例。

R5 = (x + y + z)R5

使用身份∅ + x = x

R5 = (x + y + z)R5 + ∅

将 Arden 定理应用于 R5:

R5 = (x + y + z)*∅

使用身份∅x = x∅ = ∅

R5 = ∅

身份∅x = x∅ = ∅也会在R5代入其他方程时生效,导致R5项消失。

【讨论】:

  • 哇,谢谢。没想到会有这么深入的回答,我想教授也不会,但是非常感谢!
  • @HugoDozois:我以为是 inf。循环表达式意味着闭包*?
  • @HugoDozois:如果您按照上述步骤操作,这是可能的。由于存在 DFA,并且您可以验证 DFA 是否正确,因此将存在一个匹配不连续出现 x、y、z 的字符串的正则表达式。
  • @HugoDozois:最终表达式没有递归属性。实际上,它变成了一个重复序列(可能跟在某个字符串之后或之前),保证不包含相邻的重复字符——不是你直接考虑就能得出的。
  • @Coder-Man:最终状态意味着您可以在此处以空字符串 (lambda) 结束,或者消耗更多字符以转换到其他状态。非最终状态只有转换到其他状态的选项,所以没有空字符串(lambda)
【解决方案2】:

这应该做你想做的:

^(?!.*(.)\1)[xyz]*$

(显然,仅在具有前瞻功能的引擎上)

内容本身由第二部分处理:[xyz]*(任意数量的 x、y 或 z 字符)。锚^...$ 在这里说它必须是整个字符串。并且特殊条件(没有相邻对)由负前瞻(?!.*(.)\1) 处理,这表示字符串中的任何位置都不能有一个字符后跟相同的字符。

【讨论】:

    【解决方案3】:

    我今天走路时有一个想法并将其放在正则表达式上,但我还没有找到它不正确匹配的模式。所以这里是正则表达式:

    ^((y|z)|((yz)*y?|(zy)*z?))?(xy|xz|(xyz(yz|yx|yxz)*y?)|(xzy(zy|zx|zxy)*z?))*x?$
    

    这是一个fiddle

    如果您发现模式不匹配,请告诉我,我会尝试修改它!我知道这有点晚了,但我真的为我无法解决它而烦恼。

    【讨论】:

      【解决方案4】:

      我知道这是一个相当古老的问题,并且也有一个经过批准的解决方案。但随后我针对相同情况发布了另外 1 个可能且快速的解决方案,您希望在其中检查包含连续字符的正则表达式。

      使用下面的正则表达式:

      String regex = "\\b\\w*(\\w)\\1\\1\\w*";
      

      列出上述表达式返回结果的可能情况。

      案例 1:abcdddd 或 123444

      结果:匹配

      案例 2:abcd 或 1234

      结果:不匹配

      案例 3:&*%$$$(特殊字符)

      结果:不匹配

      希望这会有所帮助... 谢谢:)

      【讨论】:

        猜你喜欢
        • 2015-10-28
        • 1970-01-01
        • 1970-01-01
        • 2015-07-22
        • 1970-01-01
        • 2022-11-24
        • 1970-01-01
        • 2012-01-15
        • 1970-01-01
        相关资源
        最近更新 更多