在regex101中徘徊几分钟后,我意识到]
不需要转义,如果它立即跟随[
。
在regex101中,模式[]-a-z]
被描述为
/[]-a-z]/ []-a-z] match a single character present in the list below ]-a a single character in the range between ] and a (case sensitive) -z a single character in the list -z literally (case sensitive)
但我一直认为,如果-
必须在字面上匹配而不进行转义,则应该either go at the beginning, or at end。
然后为什么我的模式不会被识别为错误?为什么-z
字面上匹配列表-z
中的单个字符?
答案 0 :(得分:3)
让我们分解一下:
[]-a-z]
^^ ^
|| +---- 3
|+------ 2
+------- 1
1
是文字]
,因为它出现在模式的开头,而[]
是PCRE中无效的字符类。
2
连字符因此是班级中的第二个字符,并引入了]
和a
之间的范围。
下一个连字符3
按字面处理,因为前一个标记a
是前一个范围的结尾。此时不能引入另一个范围。在PCRE中,如果-
位于无法引入范围或转义范围的地方,则会对其进行字面处理。我们通常将字面连字符放在范围的开头或结尾以使其显而易见,但这不是必需的。
然后,z
是一个简单的文字。
PCRE遵循Perl语法。这是documented,如此:
关于]
:
]
通常是POSIX字符类的末尾(参见下面的POSIX字符类),或者它标示括号字符类的结尾。如果要在字符集中包含]
,则通常必须将其删除 但是,如果]
是 first (或第二个,如果第一个字符是插入符号)是括号中的字符类,则不表示类的结尾(因为你不能有一个空类),并被认为是可以匹配而不转义的字符集的一部分。
关于连字符:
如果字符类中的连字符在语法上不能成为范围的一部分,例如因为它是字符类的第一个或最后一个字符,或者它紧跟在范围,连字符不是特殊的,因此被认为是字面上匹配的字符。如果你想要匹配你的字符集中的连字符并且它在类中的位置使得它可以被认为是范围的一部分,你必须用反斜杠来转义该连字符。
请注意,这是指Perl语法。其他风格可能有不同的行为。例如,[]
是JavaScript中无效的(空)字符类。
问题在于,根据选项,PCRE也可以用JS方式解释这个(有几个JS兼容性标志)。来自PCRE2 docs:
开头方括号引入了一个字符类,以一个右方括号结束。默认情况下,关闭方括号本身并不特殊。如果需要结束方括号作为类的成员,它应该是类中的第一个数据字符(在初始抑扬符之后,如果存在)或使用反斜杠转义。这意味着,默认情况下,无法定义空类。 但是,如果设置了
PCRE2_ALLOW_EMPTY_CLASS
选项,则开头的结束方括号会结束(空)类。
关于连字符的记录的PCRE行为不出所料地与Perl行为相匹配:
减号(连字符)字符可用于指定字符类中的字符范围。例如,
[d-m]
匹配d和m之间的任何字母,包括端点。如果类中需要减号,则必须使用反斜杠进行转义,或者将其显示在无法解释为指示范围的位置,通常作为类中的第一个或最后一个字符,或者在一个范围之后立即。 例如,[b-d-z]
匹配b
到d
范围内的字母,连字符或z
。
答案 1 :(得分:2)
字符类中其他位置的连字符它们无法形成 范围可能被解释为文字或错误。正则表达的味道是 这个很不一致。
所以,这里-
不能形成一个范围,因为前一个标记是一个范围而不是字符,因此它被解释为文字-
答案 2 :(得分:1)
正则表达式不会失败,因为-
表示此处的范围,从]
到a
。 ]
不必在字符类中的起始位置进行转义,因此在此处将其视为文字。字符类有效,因为]
具有93
ASCII码,a
在ASCII表中有97
个代码。
修改强>
关于正则表达式,有一件事是普遍的:它们从左到右进行分析。因此,使用第一连字符周围的第一个字符形成范围。第二个连字符紧跟在范围结束字符之后,因为它被“占用”,所以它不能用作起始范围字符。因此,正则表达式引擎不能只解析第二个连字符作为文字
请参阅PCRE Reference:
减号(连字符)字符可用于指定范围 charac- 在角色类中。例如,[d-m]匹配任何字母 在d和m之间,包括在内。如果a中需要减号 类,它必须使用反斜杠转义或出现在某个位置 它不能被解释为指示范围,通常为 类中的第一个或最后一个字符,或紧跟在范围之后。对于 例如,[b-d-z]匹配b到d范围内的字母,连字符 - ter,或z。