说明:我需要这个正则表达式在ECMAScript中工作
我想找到一个匹配的正则表达式:
- 出现给定次数(当然至少一次)的唯一组,
为简单起见,我们假设(目前)每个组只有一个字符。
然后,对于组大小为1、2和3的3个(唯一的)组/字符(这些是任意参数),我们想要匹配:
aaabbc
xxxyyz
ababac
ccbabc
不能匹配:
aaaaaa
aaabbcc
aabbcd
更多示例请参见此链接:https://regex101.com/r/zpNLHw/2
<标题>试图解决方案使用正向前看和负向前看相结合来强制组是唯一的(首先,捕获第一个组,然后在捕获第二个组时,插入一个负向前看,以确保第二个组不同于第一个组,等等)。
在前瞻之后,只需附加
^.{total_number_of_characters}$
(在本例中为3 + 2 + 1 = 6
)。
导致的正则表达式:
(?=.*(.).*1.*1)(?=.*(?!1)(.).*2)(?=.*(?!1|2)(.))^.{6}$
这个尝试的解决方案似乎部分工作-它没有给出错误的匹配,但只有所需匹配的一个子集(请参阅上面的链接了解详细信息)。
正确的匹配:
aabccc
aabbbc
aaabbc
缺少匹配(应该匹配但不匹配):
abbccc
abbbcc
aaabcc
这里的逻辑是您需要首先检查较长的模式。原因是,一旦查找头是原子的(至少,在您使用的regex风格中),并且一旦它们找到匹配,当regex引擎尝试回溯时,它们永远不会被重新输入/重新计算。
如果以aaadcc
输入为例,您将很容易看到发生了什么。^(?=.*(.).*1.*1)(?=.*(?!1)(.))(?=.*(?!1|2)(.).*3).{6}$
模式首先检查3个相同的字符,然后检查与Grpup 1中捕获的字符不相等的单个字符,然后搜索除第1组和第2组之外的字符的两次出现。看一下:
- 一旦regex引擎找到三个
a
并且a
保存在Group 1缓冲区中,就退出第一个向前看。 - 第二次向前看是这样工作的:
.*
匹配整个aaadcc
字符串,然后触发负向前看并通过,但(.)
失败(因为有字符串的结束)。因此,引擎回溯,(.)
匹配并捕获c
字符到组2。 (?=.*(?!1|2)(.).*3)
现在搜索一个不等于a
和c
的字符,并且至少重复两次-但是字符串中只有一个d
。不会发生重新求值,因为查找头是原子的,发生故障。
注意:如果您使用非原子查找头(如PCRE2中的那些),您将获得预期的结果:
^(?*.*(.).*1.*1)(?*.*(?!1)(.))(?*.*(?!1|2)(.).*3).{6}$
这只是部分答案——它给出了我们需要的正则表达式,但并没有解释为什么前面的尝试不起作用。
事实证明,指定组的顺序很重要,尽管我真的不明白为什么(如果能解释一下,我将非常感激)。
最初,我们有:
(?=.*(.).*1.*1)(?=.*(?!1)(.))(?=.*(?!1|2)(.).*3)^.{6}$
;即按3, 1, 2
的顺序指定的组。
工作的正则表达式几乎相同,除了它使用3, 2, 1
的顺序(第一组想要大小为3,第二组想要大小为2,第三组想要大小为1):
(?=.*(.).*1.*1)(?=.*(?!1)(.).*2)(?=.*(?!1|2)(.))^.{6}$
到工作正则表达式的链接:https://regex101.com/r/wTHAma/1
获取仅聚集的项。
仍然是无序簇,但是组1、3、5包含了1、2、3
字符簇的字符。你可以对第1、3、5组的匹配位置进行排序,得到字符顺序,例如aaabbc
将是3 2 1
匹配位置顺序的字符数。
(?m)^(?:(?!1|3|5)(?:(.)()|(.)3()|(.)55())){3}(?=246)$
https://regex101.com/r/O8Pmgs/1
仅使用查找头获取非聚集字符,
这似乎对我有用。这个可能无法获得顺序,例如bcbbac
将是? ? ?
,即使它将正确匹配。
(?m)^(?=.*?(.).*?1.*?1)(?=.*?(?!1)(.).*?2)(?=.*?(?!1|2)(.)).{6}$
https://regex101.com/r/WdTw1u/1