非固定长度的后视

时间:2017-06-16 16:43:56

标签: c# regex

我正在尝试编写一个正则表达式来匹配空字符串,前面是元音和ck,或者是元音和任何其他辅音(来自CodeGolf的挑战)。到目前为止,我想出了(?<=[aeiou](?:ck|[^aeiou]))。这样做的问题是ck[^aeiou]之后不匹配。在cnickel的情况下,它始终在nic-kel后匹配。为什么会这样?

2 个答案:

答案 0 :(得分:2)

我认为你需要

(?<=[aeiou](?:(?!ck)[a-zA-Z-[aeiou]]|ck))

请参阅regex demo

Lookbehind是一种非消费模式 - 在未发送的情况下 - 在字符串中的每个位置进行尝试。由于您允许将前面的位置与元音和任何字符(但是元音)进行匹配,因此您将获得ck以及ke之间的匹配。

如果您希望在元音跟随任何辅音之后匹配位置,而不是在ck群集使用(?!ck)负前瞻(?!ck)的辅音模式时调整。辅音必须与[a-zA-Z-[aeiouAEIOU]]匹配。这匹配任何ASCII字母,但aeiou(不区分大小写)。

答案 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);