没有连续 2 个 a 和 b 的正则表达式
Regex with no 2 consecutive a's and b's
我最近一直在尝试一些正则表达式。现在,我有 3 个符号 a、b 和 c。
我先看了一个不想连续2个a的案例。正则表达式类似于:
((b|c + a(b|c))*(a + epsilon)
现在我想知道是否有一种方法可以概括这个问题,比如:
没有两个连续的 a 和两个连续的 b 的正则表达式。我试过类似的东西:
(a(b|c) + b(a|c) + c)* (a + b + epsilon)
但是它接受诸如 "abba" 或 "baab" 之类的输入,它们将有 2 个连续的 a(或 b),这不是我想要的。任何人都可以建议我出路吗?
如果您不能进行否定匹配,那么也许您可以使用否定前瞻来排除匹配 aa
和 bb
的字符串?类似于以下内容(有关详细信息,请参阅 Regex 101):
(?!.*(aa|bb).*)^.*$
我(认为我)通过手绘一个有限状态机解决了这个问题,然后使用 FSM2Regex 生成一个正则表达式。状态机写在下面(使用网站的语法):
#states
s0
s1
s2
s3
#initial
s0
#accepting
s1
s2
s3
#alphabet
a
b
c
#transitions
s0:a>s1
s0:b>s2
s0:c>s3
s1:b>s2
s1:c>s3
s2:a>s1
s2:c>s3
s3:c>s3
s3:a>s1
s3:b>s2
如果你看一下转换,你会发现它相当简单——我有对应于字母表中每个字母的 "sink" 的状态,我只允许从该状态转换出其他字母字母(不是 "sink" 字母)。例如,s1
是 a
的 "sink"。从所有其他州,您可以使用 a
到达 s1
。但是,一旦进入 s1
,您只能使用 b
或 c
退出它,它们有自己的 "sinks" s2
和s3
分别。因为我们可以重复 c
,所以 s3
在字符 c
上有一个到自身的过渡。将块文本粘贴到站点中,它会为您绘制所有内容,并生成正则表达式。
它为我生成的正则表达式是:
c+cc*(c+$+b+a)+(b+cc*b)(cc*b)*(c+cc*(c+$+b+a)+$+a)+(a+cc*a+(b+cc*b)(cc*b)*(a+cc*a))(cc*a+(b+cc*b)(cc*b)*(a+cc*a))*(c+cc*(c+$+b+a)+(b+cc*b)(cc*b)*(c+cc*(c+$+b+a)+$+a)+b+$)+b+a
我敢肯定,这不是最优的 :)
编辑:生成的正则表达式使用 +
作为选择运算符(我们编码人员通常称为 |
),这意味着它可能不适合粘贴到代码中。但是,我太害怕更改它并冒着破坏我的正则表达式的风险:)
您可以使用反向引用来匹配前一个字符
string input = "acbbaacbba";
string pattern = @"([ab])";
var matchList = Regex.Matches(input, pattern);
此模式将匹配:bb、aa 和 bb。如果您的输入模式中没有任何匹配项,则意味着它不包含重复的 a 或 b。
解释:
([ab]): 定义一个组,你可以在这里扩展你的符号
\1:反向引用组,例如,当匹配 'a' 时,\1 将是 'a'
我最近一直在尝试一些正则表达式。现在,我有 3 个符号 a、b 和 c。
我先看了一个不想连续2个a的案例。正则表达式类似于:
((b|c + a(b|c))*(a + epsilon)
现在我想知道是否有一种方法可以概括这个问题,比如:
没有两个连续的 a 和两个连续的 b 的正则表达式。我试过类似的东西:
(a(b|c) + b(a|c) + c)* (a + b + epsilon)
但是它接受诸如 "abba" 或 "baab" 之类的输入,它们将有 2 个连续的 a(或 b),这不是我想要的。任何人都可以建议我出路吗?
如果您不能进行否定匹配,那么也许您可以使用否定前瞻来排除匹配 aa
和 bb
的字符串?类似于以下内容(有关详细信息,请参阅 Regex 101):
(?!.*(aa|bb).*)^.*$
我(认为我)通过手绘一个有限状态机解决了这个问题,然后使用 FSM2Regex 生成一个正则表达式。状态机写在下面(使用网站的语法):
#states
s0
s1
s2
s3
#initial
s0
#accepting
s1
s2
s3
#alphabet
a
b
c
#transitions
s0:a>s1
s0:b>s2
s0:c>s3
s1:b>s2
s1:c>s3
s2:a>s1
s2:c>s3
s3:c>s3
s3:a>s1
s3:b>s2
如果你看一下转换,你会发现它相当简单——我有对应于字母表中每个字母的 "sink" 的状态,我只允许从该状态转换出其他字母字母(不是 "sink" 字母)。例如,s1
是 a
的 "sink"。从所有其他州,您可以使用 a
到达 s1
。但是,一旦进入 s1
,您只能使用 b
或 c
退出它,它们有自己的 "sinks" s2
和s3
分别。因为我们可以重复 c
,所以 s3
在字符 c
上有一个到自身的过渡。将块文本粘贴到站点中,它会为您绘制所有内容,并生成正则表达式。
它为我生成的正则表达式是:
c+cc*(c+$+b+a)+(b+cc*b)(cc*b)*(c+cc*(c+$+b+a)+$+a)+(a+cc*a+(b+cc*b)(cc*b)*(a+cc*a))(cc*a+(b+cc*b)(cc*b)*(a+cc*a))*(c+cc*(c+$+b+a)+(b+cc*b)(cc*b)*(c+cc*(c+$+b+a)+$+a)+b+$)+b+a
我敢肯定,这不是最优的 :)
编辑:生成的正则表达式使用 +
作为选择运算符(我们编码人员通常称为 |
),这意味着它可能不适合粘贴到代码中。但是,我太害怕更改它并冒着破坏我的正则表达式的风险:)
您可以使用反向引用来匹配前一个字符
string input = "acbbaacbba";
string pattern = @"([ab])";
var matchList = Regex.Matches(input, pattern);
此模式将匹配:bb、aa 和 bb。如果您的输入模式中没有任何匹配项,则意味着它不包含重复的 a 或 b。
解释:
([ab]): 定义一个组,你可以在这里扩展你的符号
\1:反向引用组,例如,当匹配 'a' 时,\1 将是 'a'