Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/regex/19.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Regex 简化正则表达式?_Regex - Fatal编程技术网

Regex 简化正则表达式?

Regex 简化正则表达式?,regex,Regex,我有以下正则表达式: (?i:^TPI$|^TIP$|^IPT$|^ITP$|^PIT$|^PTI$|^IP$|^PI$|^TI$|^IT$|^PT$|^TP$|^T$|^P$|^I$) 我如何简化它?我的正则表达式知识相当有限 我的要求是: 可接受的输入为T、P和I 值可以以任何顺序出现 每个值只接受一个。TTI无效,但TI有效 不区分大小写 我曾经 ^(?i:[TPI]){1,3}$ 在过去,这基本上是可行的。唯一的问题是它接受多个值TTT可以接受该正则表达式,我需要它失败。我们可以用另

我有以下正则表达式:

(?i:^TPI$|^TIP$|^IPT$|^ITP$|^PIT$|^PTI$|^IP$|^PI$|^TI$|^IT$|^PT$|^TP$|^T$|^P$|^I$)
我如何简化它?我的正则表达式知识相当有限

我的要求是:

可接受的输入为T、P和I 值可以以任何顺序出现 每个值只接受一个。TTI无效,但TI有效 不区分大小写 我曾经

^(?i:[TPI]){1,3}$

在过去,这基本上是可行的。唯一的问题是它接受多个值TTT可以接受该正则表达式,我需要它失败。

我们可以用另一种方式尝试。您所做的尝试允许一些您不想要的字符串通过。也就是说,一切都是重复的。在下文中,我将对PowerShell进行一些实验,以展示解决方案。首先,我们需要所有可能的字符串作为输入:

$tests = 'TPI'[0..2]|%{$a=$_;"$a"; 'TPI'[0..2]|%{$b=$_;"$a$b"; 'TPI'[0..2]|%{"$a$b$_"}}} | sort
这将产生以下值序列,我将它们格式化在一行上,但通常每行输出一个值:

$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
这当然也是正则表达式的作用

^(?i:[TPI]){1,3}$
会匹配的

我们可以通过使用所谓的负先行断言来限制我们想要匹配的内容,该断言仅在某些文本在后面时才匹配,但实际上不匹配文本本身,从而允许您使用上面的模式捕获它。这可以用什么来完成?!在其中,您将在!之后插入一些子表达式!。让我们试着限制输入不是以两个I、两个P或两个t开头:

正如你所看到的,这些都从结果中消失了。如果我们使用一个捕获组和一个反向引用,我们可以简化这个过程。括号通常以?开头的除外?捕获它们内部的匹配内容,您可以在匹配后使用这些内容从匹配中提取零件或进行替换。但是你也可以在很多正则表达式引擎的模式中使用它,事实上,我认为没有一个引擎在模式中允许负向前看,但不允许反向引用。因此,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
这个。?开始时说“匹配一个角色或不匹配”,这扩展了我们之前的两个字符,最后排除了重复的匹配。对于第二组,我们只需要排除看起来像..\1的匹配,即一个字母,后跟另一个字母,然后是第一个字母的重复。我们可以扩展上面的正则表达式,只需添加另一个.?,即捕获组和反向引用之间的可选字母:

$tests -match '^(?!.?(.).?\1)(?i:[TPI]{1,3})$'
I IP IPT IT ITP P PI PIT PT PTI T TI TIP TP TPI
现在正是您想要表示的集合。最后一个正则表达式是

^(?!.?(.).?\1)(?i:[TPI]{1,3})$
肯定比以前短了。它是否更简单可能有待讨论,因为它可能需要一些解释它的作用。对于另一个答案中更为压缩的方法,情况可能更为如此。它确实更短,但这是我的答案,我们争夺选票,我不得不说我不喜欢它;-。。。只是开玩笑。但对于这样的事情,我想将基本模式与排除分离确实对可读性有意义

另一种选择可能是使用regex验证基本模式,即初始方法。然后使用代码拒绝看起来像

($s.ToLowerInvariant().ToCharArray() | select -Unique).Count -eq $s.Length

取决于你的语言——前提是它使这些内容变得简单易读。

为了子孙后代,这里有另一个答案

^(?i:([TPI])(?!.*?\1)){1,3}$

Jaanus:这应该与这个问题的几乎所有答案都无关,除非你使用的是非常简单的实现或者是20世纪70年代左右的实现。仅供参考,我已经添加了ITP,如果它不应该在那里,请删除。不应该是,这个问题真的很好,你给出的答案非常棒。如果它是固定长度的3,我会回答/?:T|P|I{3}\1\2\3/但是对于这样的任务,你的更简单。好的,重写整个内容,因为OP说他们对正则表达式不太了解。所以我认为一个描述和一步一步的介绍会很好。谢谢!这是一个巨大的帮助。
^(?i:([TPI])(?!.*?\1)){1,3}$