具有重复字符的正则表达式

时间:2012-12-03 02:36:43

标签: regex computer-science

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

这是一个例子

xyzxzyz =传递

xyxyxyx =传递

xxyzxz =失败(重复x)

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

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

修改

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

4 个答案:

答案 0 :(得分:13)

通常对于这类问题,如果正则表达式不够简单直接派生,你可以从绘制DFA开始并从那里派生正则表达式。

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

DFA

有几种方法可以为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 = ∅

当R5被替换为其他等式时,身份∅x = x∅ = ∅也将生效,导致R5的术语消失。

答案 1 :(得分:3)

这应该做你想要的:

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

(显然,仅适用于具有前瞻性的引擎)

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

答案 2 :(得分:1)

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

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

这是一个fiddle来配合它!

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

答案 3 :(得分:0)

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

使用下面的正则表达式:

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

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

情况 1:abcdddd 或 123444

结果:匹配

情况 2:abcd 或 1234

结果:不匹配

情况 3:&*%$$$(特殊字符)

结果:不匹配

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