字符类减法
字符类减法
XML Schema,XPath,.NET(2.0版及更高版本)和JGsoft regex样式支持字符类减法。它使得匹配一个列表(character class)中存在的任何单个字符,但不匹配另一个列表(subtract class)中存在的任何单个字符变得容易。语法为[class-[subtract]]
。如果连字符后的字符是一个开括号,则这些样式会将连字符解释为减法运算符,而不是范围运算符。我们可以在减去的字符类中使用完整字符类语法。
字符类[a-z-[aeiuo]]
匹配单个字母是不是元音。换句话说:它匹配单个辅音。如果没有字符类减法或交集,那么唯一的方法就是列出所有辅音:[b-df-hj-np-tv-z]
。
字符类[\p{Nd}-[^\p{IsThai}]]
匹配任何单个泰文数字。基类与任何Unicode数字匹配。从该类别中减去所有非泰文字符。[\p{Nd}-[\P{IsThai}]]
也是一样。[\p{IsThai}-[^\p{Nd}]]
和[\p{IsThai}-[\P{Nd}]]
也通过从泰文字符中减去所有非数字来匹配单个泰文数字。
嵌套字符类减法
由于可以在减除的字符类中使用完整字符类语法,因此可以从要减去的类中减去一个类。[0-9-[0-6-[0-3]]]
第一减去0-3从0-6,得到[0-9-[4-6]
,或[0-37-9]
,其匹配目标字符串0123789中的任何字符。
类减法必须始终是字符类中的最后一个元素。[0-9-[4-6]a-f]
不是有效的正则表达式。应该将其重写为[0-9a-f-[4-6]]
。减法适用于整个类。例如[\p{Ll}\p{Lu}-[\p{IsBasicLatin}]]
匹配所有大写和小写Unicode字母,但不包括任何ASCII字母。\p {IsBasicLatin}
是从组合\p{L1}\p{Lu}
中被减去的。而不是单独从\p{Lu}
中减去。此正则表达式将与abc不匹配。
虽然可以使用嵌套字符类减法,但是不能顺序地减去两个类。要从具有所有Unicode字母的类中减去ASCII字符和希腊字符,请将ASCII和希腊字符组合为一个类,然后将其减去,如[\p{L}-[\p{IsBasicLatin}\p{IsGreek}]]
。
否定优先于减法
字符类[^1234-[3456]]
既被取反又被减去。在所有支持字符类减法的风格中,在减去基类之前都将其取反。此类应读为“(非1234)减去3456”。因此,此字符类与数字1、2、3、4、5和6以外的任何字符匹配。
与其他Regex的符号兼容性
需要注意的是像一个正则表达式[a-z-[aeiuo]]
不引起不支持字符类减法最正则表达式的语言的任何错误。但这也不符合我们的预期。在大多数语言中,此正则表达式由字符类和后跟一个字符]组成。字符类与a-z或连字符,或方括号或元音范围内的字符匹配。由于a-z范围和元音是多余的,因此我们可以在Perl中将此字符类写为[a-z-[]
或[-[a-z]]
。范围后的连字符被当作文本字符,就像左括号后面的连字符一样。在XML,.NET和JGsoft中也是如此。[a-z-_]
匹配这些样式中的小写字母,连字符或下划线。
严格来说,这意味着字符类减法语法与Perl和大多数其他正则表达式风格不兼容。但是实际上没有什么区别。在字符类范围内使用非字母数字字符是非常不好的做法,因为它依赖于ASCII字符表中字符的顺序。这使得在我们之后工作的程序员很难理解正则表达式。虽然[A-[]
会匹配Perl中的任何大写字母或方括号,但是当将其写为[A-Z[]
时,此正则表达式会更加清晰。前一个正则表达式会导致XML,.NET和JGsoft风格出错,因为它们将-[]
解释为空的减法类,从而导致不成对儿的[
。