我正在尝试编写一个正则表达式来匹配空字符串,前面是元音和ck
,或者是元音和任何其他辅音(来自CodeGolf的挑战)。到目前为止,我想出了(?<=[aeiou](?:ck|[^aeiou]))
。这样做的问题是ck
与[^aeiou]
之后不匹配。在c
:nickel
的情况下,它始终在nic-kel
后匹配。为什么会这样?
答案 0 :(得分:2)
我认为你需要
(?<=[aeiou](?:(?!ck)[a-zA-Z-[aeiou]]|ck))
请参阅regex demo。
Lookbehind是一种非消费模式 - 在未发送的情况下 - 在字符串中的每个位置进行尝试。由于您允许将前面的位置与元音和任何字符(但是元音)进行匹配,因此您将获得c
和k
以及k
和e
之间的匹配。
如果您希望在元音跟随任何辅音之后匹配位置,而不是在ck
群集使用(?!ck)
负前瞻(?!ck)
的辅音模式时调整。辅音必须与[a-zA-Z-[aeiouAEIOU]]
匹配。这匹配任何ASCII字母,但a
,e
,i
,o
,u
(不区分大小写)。
答案 1 :(得分:1)
你的正则表达式没有任何问题,只需添加一个简单的(?!ck)
在辅音之前。
(?<=([aeiou](?:ck|(?!ck)[^aeiou])))
(?<=
( # (1 start)
[aeiou]
(?:
ck
| (?! ck ) # <== here
[^aeiou]
)
) # (1 end)
)
但是,你可能想知道原因。
原因是在C#中的可变长度外观上 它从一个角色之间的一个点开始。
在任何时候,只有那一点,它会向后看一场比赛 在比赛中不允许所有提前。
让我们看看他们是如何做到的:
使用正则表达式(?<=[aeiou](?:ck|[^aeiou]))
i
&lt; =绝对位置ck
,然后回顾
查找[aeiou]
。
失败ck
和[^aeiou]
前进(右)1个位置,然后回头看
ic
&lt; =绝对位置k
失败ck
但是,匹配&#39; c&#39;与[^aeiou]
要记住的重要一点是,它不能违背自己的意图 两个主要规则。
他们的规则规定必须采取它找到的第一场比赛,
它必须发现它在人物之间向后看。
因此,很明显,如果找到并匹配此ic
&lt; =绝对位置k
第一。
每个断言都在其自身的相对帧位置中
独立于它的周围代码。
该位置是动态的(变化的),它的起源是当前位置
调用表达式(甚至是另一个断言)。
因此,当在断言中调用断言时,它只需要父母当前的位置,并在内部进行检查。 保持它拥有当前位置。
让我们看看修复做(?<=[aeiou](?:ck|(?!ck)[^aeiou]))
i
&lt; =绝对位置ck
,然后回顾
查找[aeiou]
。
失败ck
和[^aeiou]
前进(右)1个位置,然后回头看
ic
&lt; =绝对位置k
注意,在内部,它匹配向前和
相对位置现在在这里=&gt; ck
因为它已经匹配i
并且正在检查它。
由于“{&n;会将1个字符扩展到其中 绝对位置
然而,它可以匹配&#39; c&#39;与ck
没有超越它的绝对位置
要停止,[^aeiou]
之前只需要一个简单的(?!ck)
此时[^aeiou]
传递此相对位置,并且它为
不受呼叫者绝对位置的限制。
它看到有一个(?!ck)
期待并返回错误的情况
使外部断言失败。
前进(右)1个位置,然后回头看
ck
&lt; =绝对位置,然后回头看
这次它在ick
演示
目标字符串
ick
C#
nickel : nic-ikel
输出
string Stxt = "nickel : nic-ikel";
var RxR = new Regex(@"(?<=([aeiou](?:ck|(?!ck)[^aeiou])))");
foreach (Match match in RxR.Matches(Stxt))
Console.WriteLine("{0}", match.Groups[1].Value);