我有以下正则表达式:
(?i:^TPI$|^TIP$|^IPT$|^ITP$|^PIT$|^PTI$|^IP$|^PI$|^TI$|^IT$|^PT$|^TP$|^T$|^P$|^I$)
Run Code Online (Sandbox Code Playgroud)
我该如何简化它?我的正则表达知识相当有限.
我的要求是:
我用了
^(?i:[TPI]){1,3}$
Run Code Online (Sandbox Code Playgroud)
在过去,这主要是有效的.唯一的问题是它接受多个值"TTT"是可以接受的正则表达式,我需要它失败).
我们可以尝试不同的方式.你做的尝试允许一些字符串滑过你不想要的.也就是说,一切都是重复的.在下文中,我将使用PowerShell进行一些实验来展示解决方案.首先,我们需要所有可能的字符串作为输入:
$tests = 'TPI'[0..2]|%{$a=$_;"$a"; 'TPI'[0..2]|%{$b=$_;"$a$b"; 'TPI'[0..2]|%{"$a$b$_"}}} | sort
Run Code Online (Sandbox Code Playgroud)
这会产生以下值序列(我在一行上格式化它们,但它们通常每行出一个):
$tests
I II III IIP IIT IP IPI IPP IPT IT ITI ITP ITT P PI PII PIP PIT PP PPI PPP PPT PT PTI PTP PTT T TI TII TIP TIT TP TPI TPP TPT TT TTI TTP TTT
Run Code Online (Sandbox Code Playgroud)
这当然也是正则表达式
^(?i:[TPI]){1,3}$
Run Code Online (Sandbox Code Playgroud)
会匹配.
我们可以通过使用所谓的负前瞻断言来限制我们想要匹配的内容,该断言仅在某些文本跟随但实际上不匹配文本本身时才匹配,从而允许它由上面的模式捕获.这可以通过(?!)在后面插入一些子表达式来完成!.让我们尝试限制输入不以两个I,两个P或两个开头T:
$tests -match '^(?!II|PP|TT)(?i:[TPI]{1,3})$'
I IP IPI IPP IPT IT ITI ITP ITT P PI PII PIP PIT PT PTI PTP PTT T TI TII TIP TIT TP TPI TPP TPT
Run Code Online (Sandbox Code Playgroud)
正如您所看到的那样,结果已经消失了.如果我们使用捕获组和反向引用,我们可以简化它.括号通常(除非它们以它们开头(?)捕获它们内部匹配的内容,您可以在匹配后使用它来从匹配中提取部分或替换.但是你也可以在许多正则表达式引擎中使用它在模式中(事实上,我认为没有引擎允许负向前瞻但在模式中没有反向引用).所以II|PP|TT可以写成(.)\1只是说"一个字母,后跟完全相同的字母",因为\1是反向引用,指向匹配的任何东西(.).
现在我们仍然有一些我们不想要的值,即位置2和3中的两个相同字母以及位置1和3中的所有值.我们可以通过以下方式摆脱前者:
$tests -match '^(?!.?(.)\1)(?i:[TPI]{1,3})$'
I IP IPI IPT IT ITI ITP P PI PIP PIT PT PTI PTP T TI TIP TIT TP TPI TPT
Run Code Online (Sandbox Code Playgroud)
将.?在开始现在说"相匹配的字符或没有"的延伸,因此我们有什么前两排除比赛用到底重复.对于第二组,我们只需要排除看起来像的匹配(.).\1,即一个字母,然后是另一个,然后重复第一个.我们可以通过添加另一个.?,即捕获组和反向引用之间的可选字母来扩展上面的正则表达式:
$tests -match '^(?!.?(.).?\1)(?i:[TPI]{1,3})$'
I IP IPT IT ITP P PI PIT PT PTI T TI TIP TP TPI
Run Code Online (Sandbox Code Playgroud)
现在正是您想要表示的集合.最终的正则表达式是
^(?!.?(.).?\1)(?i:[TPI]{1,3})$
Run Code Online (Sandbox Code Playgroud)
它比以前更短,这是肯定的.它是否更简单可能需要辩论,因为它可能需要一些解释它的作用.对于另一个答案中更加压缩的方法,情况可能更为明显.它确实更短,但这是我的答案,我们争取选票,我只是说我不喜欢它;-) ......开个玩笑.但对于这些事情,我认为将基本模式与排除分开确实对可读性有意义.
另一种选择可能是使用正则表达式验证基本模式,即您的初始方法.然后使用代码来拒绝可能看起来像的重复项
($s.ToLowerInvariant().ToCharArray() | select -Unique).Count -eq $s.Length
Run Code Online (Sandbox Code Playgroud)
取决于您的语言 - 只要它使这些事情变得简单易读.
| 归档时间: |
|
| 查看次数: |
269 次 |
| 最近记录: |