正则表达式而不是.Contains(“ xx”)

时间:2019-02-04 16:16:57

标签: c# .net regex

我需要有一个正则表达式字符串模式,该模式告诉我我的字符串不包含两个符号'x'"aaa bbbx x gggg"-可以,但是'aaa nnnx ll xx ccx','aa xxx''aaxx bbb'-不是。 这似乎很简单,但对我来说却是挑战。

我希望它是正则表达式,而不是Contains,因为它是我的解决方案(验证属性,DataAnnotations)中标准验证的一部分,并且我不想添加自定义验证器类对于这种情况。默认有一个RegularExpressionAttribute,我最好使用它。我试图避免添加自定义类。

我知道我可以添加包含value.Contains("xx")的自定义验证属性。但这是在解决方案中添加一个以上类的简便方法。我的问题不是“如何验证财产”,而是关于正则表达式。有没有可能。至少,这很有趣。

2 个答案:

答案 0 :(得分:0)

这是您要寻找的模式:

  

^((?!xx).)*$

答案 1 :(得分:0)

最后编辑;如果您想要正确的答案,请直接跳到那里

尝试在此处添加一些价值...

因此@Rotem说他们在Google上找到了此正则表达式,并且希望获得一些帮助以了解它:

^((?!xx).)*$

(?!<p>)语法(其中<p>是一种模式)被称为超前断言。 我比C#更了解Python,所以这里是the doc about it

  

(?!...)

     

如果..,则匹配。接下来不匹配。这是一个否定的超前断言。例如,Isaac (?!Asimov)仅在'Isaac '之后才匹配'Asimov'

因此,更好的表达方式是:

^(.(?!xx))*$

让我们分解这种模式:

^(.(?!xx))*$

^               anchor at the beginning of the string
 (       )*     any number of...
  .             ...any character...
   (?!xx)       ...follwed by anything but 'xx'
           $    anchor at the end of the string

小示范:

>>> re.match('^(.(?!xx))*$', 'abc')
<re.Match object; span=(0, 3), match='abc'>
>>> re.match('^(.(?!xx))*$', 'axbc')
<re.Match object; span=(0, 4), match='axbc'>
>>> re.match('^(.(?!xx))*$', 'axbxc')
<re.Match object; span=(0, 5), match='axbxc'>
>>> re.match('^(.(?!xx))*$', 'axbxxc')
>>> # None, ie no match

现在,为什么我刚才写的东西是错误的?

根据@WiktorStribiżew在his post中的解释,原始模式^((?!xx).)*$的解读如下:

Assert that the next two characters are not 'xx', then consume one
(any number of times)

我为什么错了? 我暗示(?!xx)是一个先行断言(成立),它需要遵循一个消耗字符,因此正确的模式是^(.(?!xx))*$。 这里的错误前提是,先行断言必须遵循消耗模式。 这完全是错误的:这样的断言仅告诉引擎查看当前指向的字符之后的字符。

现在让我们回到两种模式。 我提出的是伪造的,因为这意味着:

Consume one character, then assert the following two are not 'xx'
(any number of times)

因此在xxa中,它将使用前一个x,并确保以下两个字符不是xx:可以,因为它们是xa,所以继续匹配,最后到达终点。 因此,它匹配任何不包含xx的字符串,除非它位于开头。

另一方面,正确的模式将首先确保接下来的两个字符不是xx。由于它当前指向字符串的开始锚点,因此接下来的两个字符为xx,并且断言失败。

因此,正确的模式实际上是^((?!xx).)*$