我需要有一个正则表达式字符串模式,该模式告诉我我的字符串不包含两个符号'x'
。 "aaa bbbx x gggg"
-可以,但是'aaa nnnx ll xx ccx'
,'aa xxx'
,'aaxx bbb'
-不是。
这似乎很简单,但对我来说却是挑战。
我希望它是正则表达式,而不是Contains
,因为它是我的解决方案(验证属性,DataAnnotations
)中标准验证的一部分,并且我不想添加自定义验证器类对于这种情况。默认有一个RegularExpressionAttribute
,我最好使用它。我试图避免添加自定义类。
我知道我可以添加包含value.Contains("xx")
的自定义验证属性。但这是在解决方案中添加一个以上类的简便方法。我的问题不是“如何验证财产”,而是关于正则表达式。有没有可能。至少,这很有趣。
答案 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).)*$
。