如何构建{a,b}语言中匹配奇数个a和奇数个b的正则表达式?
嘿,我来帮你搞定这个正则问题!
首先,先说说你的正则为什么会匹配空串:你的表达式是(((aa+bb)*(ab+ba))*+((ab+ba)(aa+bb)*)*),这里最外层的两个分支都用了*——((aa+bb)*(ab+ba))*允许匹配0次,((ab+ba)(aa+bb)*)*也允许匹配0次。当两个分支都匹配0次时,整个正则就会匹配空串,这就是评分器报错的原因。
接下来,咱们来构造正确的正则,目标是匹配{a,b}语言中包含奇数个a和奇数个b的字符串。
核心思路
要满足奇数个a和奇数个b,我们可以从状态机的角度思考:
- 初始状态:偶数个a、偶数个b(空串就在这里,必须排除)
- 我们需要最终到达的状态:奇数个a、奇数个b
- 任何
aa或bb的组合不会改变a/b的奇偶性(因为加了偶数个相同字符) - 任何
ab或ba的组合会同时改变a和b的奇偶性(各加1个,奇偶翻转)
所以,正确的字符串必须包含奇数次的ab或ba(每次翻转奇偶性,奇数次翻转后从初始的偶偶变成奇奇),同时可以在任意位置插入任意数量的aa或bb。
正确的正则表达式
基于这个思路,最终的正则可以写成:
^(?:(?:aa|bb)*(?:ab|ba))(?:(?:aa|bb)*(?:ab|ba)(?:aa|bb)*(?:ab|ba))*(?:aa|bb)*$
拆解说明
(?:aa|bb)*:匹配任意数量的aa或bb(不改变奇偶性)(?:ab|ba):匹配一次ab或ba(翻转一次奇偶性,从偶偶变奇奇,或奇奇变偶偶)- 最前面的
(?:(?:aa|bb)*(?:ab|ba)):确保至少有一次奇偶翻转(避免空串) - 中间的
(?:(?:aa|bb)*(?:ab|ba)(?:aa|bb)*(?:ab|ba))*:匹配0次或多次“两次翻转”(每次两次翻转后回到奇奇状态,总翻转次数保持奇数) - 最后的
(?:aa|bb)*:允许在末尾添加任意数量的aa或bb
验证几个例子
- 空串
"":不匹配(正确,因为空串是偶偶) "ab":匹配(1a1b,奇奇)"aaabbb":匹配(3a3b,奇奇)"abab":不匹配(2a2b,偶偶)"aabbab":匹配(3a3b,奇奇)"a":不匹配(1a0b,b是偶数)
内容的提问来源于stack exchange,提问作者DerpDude21




