perlrecharclass - Perl 正则表达式字符类
有关 Perl 正则表达式的顶级文档可以在 perlre 中找到。
本手册页讨论了 Perl 正则表达式中字符类的语法和用法。
字符类是一种表示字符集的方式,以便匹配该集合中的一个字符。重要的是要记住:匹配字符类会消耗源字符串中的一个字符。(源字符串是与正则表达式匹配的字符串。)
Perl 正则表达式中有三种类型的字符类:点、反斜杠序列和方括号括起来的表单。请记住,通常“字符类”一词仅指方括号形式。当然,大多数 Perl 文档都是这样做的。
点(或句点),.
可能是最常用的,当然也是最著名的字符类。默认情况下,点匹配除换行符以外的任何字符。可以使用单行修饰符更改此默认值以添加换行符匹配:对于使用/s
修饰符的整个正则表达式,或者使用(?s)
在本地使用(甚至在 use re '/s'
的范围内全局使用)。(下面描述的"\N"
反斜杠序列匹配除换行符以外的任何字符,而不考虑单行修饰符。)
以下是一些示例
"a" =~ /./ # Match
"." =~ /./ # Match
"" =~ /./ # No match (dot has to match a character)
"\n" =~ /./ # No match (dot does not match a newline)
"\n" =~ /./s # Match (global 'single line' modifier)
"\n" =~ /(?s:.)/ # Match (local 'single line' modifier)
"ab" =~ /^.$/ # No match (dot matches one character)
反斜杠序列是一系列字符,第一个字符是反斜杠。Perl 对许多这样的序列赋予了特殊含义,其中一些是字符类。也就是说,它们分别匹配单个字符,前提是该字符属于序列定义的特定字符集。
以下是作为字符类的反斜杠序列列表。它们将在下面更详细地讨论。(对于不是字符类的反斜杠序列,请参见 perlrebackslash。)
\d Match a decimal digit character.
\D Match a non-decimal-digit character.
\w Match a "word" character.
\W Match a non-"word" character.
\s Match a whitespace character.
\S Match a non-whitespace character.
\h Match a horizontal whitespace character.
\H Match a character that isn't horizontal whitespace.
\v Match a vertical whitespace character.
\V Match a character that isn't vertical whitespace.
\N Match a character that isn't a newline.
\pP, \p{Prop} Match a character that has the given Unicode property.
\PP, \P{Prop} Match a character that doesn't have the Unicode property
\N
,从 v5.12 开始可用,与点类似,匹配任何非换行符字符。区别在于 \N
不受单行正则表达式修饰符的影响(参见上面的 "点")。请注意,\N{...}
形式可能意味着完全不同的东西。当 {...}
是一个 量词 时,它表示匹配该数量的非换行符字符。例如,\N{3}
表示匹配 3 个非换行符;\N{5,}
表示匹配 5 个或更多个非换行符。但如果 {...}
不是合法的量词,则假定它是一个命名字符。有关这些内容,请参见 charnames。例如,\N{COLON}
、\N{4F}
和 \N{F4}
中都没有合法的量词,因此 Perl 将尝试查找名称分别为 COLON
、4F
和 F4
的字符。
\d
匹配被认为是十进制数字的单个字符。如果 /a
正则表达式修饰符生效,它将匹配 [0-9]。否则,它将匹配 \p{Digit}
匹配的任何内容,其中包括 [0-9]。(一个不太可能的例外情况是,在区域设置匹配规则下,当前区域设置可能不会让 \d
匹配 [0-9]
,或者可能匹配其他代码点小于 256 的字符。唯一合法的此类区域设置定义是匹配 [0-9]
加上另外一组 10 个连续的数字字符;其他任何情况都将违反 C 语言标准,但 Perl 目前没有对此做出任何假设。)
这意味着,除非 /a
修饰符生效,否则 \d
不仅匹配数字 '0' - '9',还匹配阿拉伯语、德文那伽利语和其他语言的数字。这可能会造成一些混淆,以及一些安全问题。
\d
匹配的一些数字看起来像 [0-9] 中的一些数字,但值不同。例如,孟加拉数字四 (U+09EA) 看起来非常像 ASCII 数字八 (U+0038),而列车数字六 (U+1C46) 看起来非常像 ASCII 数字五 (U+0035)。期望仅使用 ASCII 数字的应用程序可能会被误导,或者如果匹配项是 \d+
,则匹配的字符串可能包含来自不同书写系统的数字混合,这些数字看起来像是表示一个与实际不同的数字。 "num()" in Unicode::UCD 可用于安全地计算值,如果输入字符串包含此类混合,则返回 undef
。否则,例如,显示的价格可能会故意与显示的价格不同。
\p{Digit}
的含义(以及在 /a
修饰符之外的 \d
的含义)是 \p{General_Category=Decimal_Number}
,或同义词 \p{General_Category=Digit}
。从 Unicode 版本 4.1 开始,这与 \p{Numeric_Type=Decimal}
匹配的字符集相同。但 Unicode 还具有一个名称相似的不同属性,\p{Numeric_Type=Digit}
,它匹配一组完全不同的字符。这些字符包括 CIRCLED DIGIT ONE
或下标,或者来自缺乏所有十个数字的书写系统。
设计意图是让 \d
准确地匹配可以安全地用于“正常”大端位置十进制语法的一组字符,例如,其中 123 表示一个“百”,加上两个“十”,加上三个“一”。这种位置表示法不一定适用于与其他类型的“数字”匹配的字符,\p{Numeric_Type=Digit}
,因此 \d
不匹配它们。
泰米尔数字 (U+0BE6 - U+0BEF) 也可以在旧式泰米尔数字中合法使用,在这些数字中它们最多会连续出现一次,并由表示“乘以 10”、“乘以 100”等的字符隔开。(参见 https://www.unicode.org/notes/tn21。)
任何不与 \d
匹配的字符都与 \D
匹配。
\w
匹配单个字母数字字符(字母字符或十进制数字);或连接标点符号,例如下划线(“_”);或“标记”字符(如某种重音符号),它附加到其中之一。它不匹配整个单词。要匹配整个单词,请使用 \w+
。这与匹配英语单词不同,但在 ASCII 范围内,它与 Perl 标识符字符的字符串相同。
应用哪些规则取决于 "perlre 中的“哪个字符集修饰符有效?”" 中所述。
Unicode 中完整的单词字符列表存在一些安全问题。请参阅 http://unicode.org/reports/tr36。
此外,对于超出 ASCII 范围的编程语言标识符中更细粒度的字符集,您可能希望使用更自定义的 "Unicode 属性",\p{ID_Start}
、\p{ID_Continue}
、\p{XID_Start}
和 \p{XID_Continue}
。请参阅 http://unicode.org/reports/tr31。
任何不匹配 \w
的字符都将匹配 \W
。
\s
匹配任何被视为空白字符的单个字符。
/a
修饰符有效 ...在所有 Perl 版本中,\s
匹配 5 个字符 [\t\n\f\r ];即水平制表符、换行符、换页符、回车符和空格。从 Perl v5.18 开始,它还匹配垂直制表符,\cK
。有关此问题的讨论,请参阅下面的注释 [1]
。
应用哪些规则取决于 "perlre 中的“哪个字符集修饰符有效?”" 中所述。
\s
不匹配的任何字符都由 \S
匹配。
\h
匹配任何被认为是水平空白的字符;这包括平台的空格和制表符,以及下表中列出的其他几个字符。\H
匹配任何不被认为是水平空白的字符。它们使用平台的本机字符集,并且不考虑可能使用的任何区域设置。
\v
匹配任何被认为是垂直空白的字符;这包括平台的回车符和换行符(换行符),以及其他几个字符,所有这些字符都列在下表中。\V
匹配任何不被认为是垂直空白的字符。它们使用平台的本机字符集,并且不考虑可能使用的任何区域设置。
\R
匹配任何根据 Unicode 规则可以被认为是换行符的内容。它可以匹配多字符序列。它不能在方括号字符类中使用;请改用 \v
(垂直空白)。它使用平台的本机字符集,并且不考虑可能使用的任何区域设置。详细信息在 perlrebackslash 中讨论。
请注意,与 \s
(以及 \d
和 \w
)不同,\h
和 \v
始终匹配相同的字符,而不考虑其他因素,例如活动区域设置或源字符串是否为 UTF-8 格式。
人们可能会认为 \s
等效于 [\h\v]
。从 Perl v5.18 开始,这确实是正确的,但在那之前,唯一的区别是垂直制表符 ("\cK"
) 没有被 \s
匹配。
下表是截至 Unicode 14.0 时 \s
、\h
和 \v
匹配的字符的完整列表。
第一列给出字符的 Unicode 代码点(以十六进制格式表示),第二列给出(Unicode)名称。第三列指示字符由哪些类匹配(假设没有生效的区域设置会更改 \s
匹配)。
0x0009 CHARACTER TABULATION h s
0x000a LINE FEED (LF) vs
0x000b LINE TABULATION vs [1]
0x000c FORM FEED (FF) vs
0x000d CARRIAGE RETURN (CR) vs
0x0020 SPACE h s
0x0085 NEXT LINE (NEL) vs [2]
0x00a0 NO-BREAK SPACE h s [2]
0x1680 OGHAM SPACE MARK h s
0x2000 EN QUAD h s
0x2001 EM QUAD h s
0x2002 EN SPACE h s
0x2003 EM SPACE h s
0x2004 THREE-PER-EM SPACE h s
0x2005 FOUR-PER-EM SPACE h s
0x2006 SIX-PER-EM SPACE h s
0x2007 FIGURE SPACE h s
0x2008 PUNCTUATION SPACE h s
0x2009 THIN SPACE h s
0x200a HAIR SPACE h s
0x2028 LINE SEPARATOR vs
0x2029 PARAGRAPH SEPARATOR vs
0x202f NARROW NO-BREAK SPACE h s
0x205f MEDIUM MATHEMATICAL SPACE h s
0x3000 IDEOGRAPHIC SPACE h s
在 Perl v5.18 之前,\s
不会匹配垂直制表符。[^\S\cK]
(模糊地)匹配 \s
传统上所做的匹配。
NEXT LINE 和 NO-BREAK SPACE 是否匹配 \s
取决于生效的规则。请参阅 本节开头。
\pP
和 \p{Prop}
是字符类,用于匹配符合给定 Unicode 属性的字符。单字母属性名称可以在 \pP
形式中使用,属性名称紧跟在 \p
之后,否则需要使用大括号。使用大括号时,有一种单一形式,即属性名称用大括号括起来,还有一种复合形式,看起来像 \p{name=value}
,这意味着如果字符的属性“name”具有该特定“value”,则匹配。例如,匹配数字可以写成 /\pN/
或 /\p{Number}/
,或者 /\p{Number=True}/
。小写字母由属性 Lowercase_Letter 匹配,其简写形式为 Ll。它们需要大括号,因此写成 /\p{Ll}/
或 /\p{Lowercase_Letter}/
,或 /\p{General_Category=Lowercase_Letter}/
(下划线是可选的)。/\pLl/
是有效的,但含义不同。它匹配一个两个字符的字符串:一个字母(Unicode 属性 \pL
),后跟一个小写 l
。
Unicode 属性匹配的内容永远不会受区域设置规则的影响,如果区域设置规则没有生效,则使用 Unicode 属性将强制正则表达式使用 Unicode 规则(如果尚未使用)。
请注意,几乎所有属性都对大小写不敏感匹配免疫。也就是说,添加/i
正则表达式修饰符不会改变它们匹配的内容。但有两组会受到影响。第一组是Uppercase_Letter
、Lowercase_Letter
和Titlecase_Letter
,它们在/i
匹配下都匹配Cased_Letter
。第二组是Uppercase
、Lowercase
和Titlecase
,它们在/i
匹配下都匹配Cased
。(这两组之间的区别在于,有些东西,比如罗马数字,既有大小写,所以它们是Cased
,但并不被认为是字母,所以它们不是Cased_Letter
。它们实际上是Letter_Number
。)这组还包括它的子集PosixUpper
和PosixLower
,它们在/i
匹配下都匹配PosixAlpha
。
有关 Unicode 属性的更多详细信息,请参阅"perlunicode 中的 Unicode 字符属性";有关所有可能属性的完整列表,请参阅"perluniprops 中通过 \p{} 和 \P{} 访问的属性",其中指出了所有具有/i
差异的形式。也可以定义自己的属性。这在"perlunicode 中的用户定义字符属性"中进行了讨论。
Unicode 属性仅在 Unicode 代码点上定义(不出所料!)。从 v5.20 开始,在与\p
和\P
匹配时,Perl 将非 Unicode 代码点(那些高于 0x10FFFF 的合法 Unicode 最大值)视为典型的未分配 Unicode 代码点。
在 v5.20 之前,Perl 会发出警告并在非 Unicode 代码点上使所有匹配失败。这可能有些令人惊讶
chr(0x110000) =~ \p{ASCII_Hex_Digit=True} # Fails on Perls < v5.20.
chr(0x110000) =~ \p{ASCII_Hex_Digit=False} # Also fails on Perls
# < v5.20
即使这两个匹配可能被认为是互补的,但在 v5.20 之前,它们只在 Unicode 代码点上是互补的。
从 perl v5.30 开始,允许在 Unicode 属性值中使用通配符。请参阅"perlunicode 中属性值中的通配符"。
"a" =~ /\w/ # Match, "a" is a 'word' character.
"7" =~ /\w/ # Match, "7" is a 'word' character as well.
"a" =~ /\d/ # No match, "a" isn't a digit.
"7" =~ /\d/ # Match, "7" is a digit.
" " =~ /\s/ # Match, a space is whitespace.
"a" =~ /\D/ # Match, "a" is a non-digit.
"7" =~ /\D/ # No match, "7" is not a non-digit.
" " =~ /\S/ # No match, a space is not non-whitespace.
" " =~ /\h/ # Match, space is horizontal whitespace.
" " =~ /\v/ # No match, space is not vertical whitespace.
"\r" =~ /\v/ # Match, a return is vertical whitespace.
"a" =~ /\pL/ # Match, "a" is a letter.
"a" =~ /\p{Lu}/ # No match, /\p{Lu}/ matches upper case letters.
"\x{0e0b}" =~ /\p{Thai}/ # Match, \x{0e0b} is the character
# 'THAI CHARACTER SO SO', and that's in
# Thai Unicode class.
"a" =~ /\P{Lao}/ # Match, as "a" is not a Laotian character.
值得强调的是,\d
、\w
等匹配单个字符,而不是完整的数字或单词。要匹配一个数字(由数字组成),请使用\d+
;要匹配一个单词,请使用\w+
。但请注意,如上所述,这样做存在安全问题。
在 Perl 正则表达式中,您可以使用的第三种字符类形式是方括号字符类。最简单的形式是列出要匹配的字符,用方括号括起来,例如:[aeiou]
。这将匹配 a
、e
、i
、o
或 u
中的一个。与其他字符类一样,只匹配一个字符。* 要匹配由字符类中提到的字符组成的更长的字符串,请在字符类后面加上一个 量词。例如,[aeiou]+
匹配一个或多个小写英文元音。
在字符类中重复字符没有任何效果;它只被认为是集合中的一次出现。
示例
"e" =~ /[aeiou]/ # Match, as "e" is listed in the class.
"p" =~ /[aeiou]/ # No match, "p" is not listed in the class.
"ae" =~ /^[aeiou]$/ # No match, a character class only matches
# a single character.
"ae" =~ /^[aeiou]+$/ # Match, due to the quantifier.
-------
* 方括号字符类只匹配单个字符有两个例外。每个都需要 Perl 的特殊处理才能使事情正常工作
当类在 /i
匹配规则下进行不区分大小写的匹配时,并且在类中明确提到的字符在 Unicode 规则下不区分大小写地匹配多个字符序列时,该类也将匹配该序列。例如,Unicode 规定字母 LATIN SMALL LETTER SHARP S
在 /i
规则下应匹配序列 ss
。因此,
'ss' =~ /\A\N{LATIN SMALL LETTER SHARP S}\z/i # Matches
'ss' =~ /\A[aeioust\N{LATIN SMALL LETTER SHARP S}]\z/i # Matches
为了使这种情况发生,该类不能被反转(参见 "否定"),并且该字符必须被明确指定,并且不能是多字符范围的一部分(即使作为其端点之一)。("字符范围" 将在稍后解释。)因此,
'ss' =~ /\A[\0-\x{ff}]\z/ui # Doesn't match
'ss' =~ /\A[\0-\N{LATIN SMALL LETTER SHARP S}]\z/ui # No match
'ss' =~ /\A[\xDF-\xDF]\z/ui # Matches on ASCII platforms, since
# \xDF is LATIN SMALL LETTER SHARP S,
# and the range is just a single
# element
请注意,无论如何指定这些类型的范围都不是一个好主意。
一些 \N{...}
已知名称指的是多个字符的序列,而不是通常的单个字符。当其中一个包含在类中时,将匹配整个序列。例如,
"\N{TAMIL LETTER KA}\N{TAMIL VOWEL SIGN AU}"
=~ / ^ [\N{TAMIL SYLLABLE KAU}] $ /x;
匹配,因为 \N{TAMIL SYLLABLE KAU}
是一个命名序列,它包含两个与之匹配的字符。与方括号类可以匹配多个字符的其他情况一样,出于类似的原因,该类不能被反转,并且命名序列不能出现在范围内,即使它同时是两个端点。如果发生这种情况,如果字符类在 use re 'strict
的范围内,或者在扩展的 (?[...])
类中,则将是一个致命错误;否则只使用第一个代码点(并发出 regexp
类型的警告)。
大多数在正则表达式中充当元字符的字符(即具有特殊含义的字符,例如.
、*
或(
)会失去其特殊含义,可以在字符类中使用,无需转义。例如,[()]
匹配左括号或右括号,字符类中的括号不会进行分组或捕获。请注意,除非模式在单引号上下文中进行评估,否则在解析方括号类之前会进行变量插值。
$, = "\t| ";
$a =~ m'[$,]'; # single-quotish: matches '$' or ','
$a =~ q{[$,]}' # same
$a =~ m/[$,]/; # double-quotish: Because we made an
# assignment to $, above, this now
# matches "\t", "|", or " "
在字符类中可能具有特殊含义的字符是:\
、^
、-
、[
和 ]
,将在下面讨论。它们可以使用反斜杠进行转义,尽管有时不需要,在这种情况下,可以省略反斜杠。
序列 \b
在方括号字符类中是特殊的。在字符类之外,\b
是一个断言,表示一个点,其两侧既没有两个单词字符,也没有两个非单词字符,而在方括号字符类中,\b
匹配退格字符。
序列 \a
、\c
、\e
、\f
、\n
、\N{NAME}
、\N{U+hex char}
、\r
、\t
和 \x
也是特殊的,并且具有与在方括号字符类之外相同的含义。
此外,反斜杠后跟两个或三个八进制数字被视为八进制数字。
[
在字符类中不是特殊的,除非它是 POSIX 字符类的开头(参见下面的 "POSIX 字符类")。通常不需要转义。
]
通常是 POSIX 字符类的结尾(参见下面的 "POSIX 字符类"),或者它表示方括号字符类的结尾。如果您想在字符集中包含 ]
,则通常必须对其进行转义。
但是,如果 ]
是方括号字符类的第一个(如果第一个字符是插入符号,则为第二个)字符,则它不表示类的结尾(因为不能有空类),并且被认为是可以在不转义的情况下匹配的字符集的一部分。
示例
"+" =~ /[+?*]/ # Match, "+" in a character class is not special.
"\cH" =~ /[\b]/ # Match, \b inside in a character class
# is equivalent to a backspace.
"]" =~ /[][]/ # Match, as the character class contains
# both [ and ].
"[]" =~ /[[]]/ # Match, the pattern contains a character class
# containing just [, and the character class is
# followed by a ].
/xx
模式修饰符通常,空格和制表符在方括号字符类中没有特殊含义;它们只是被添加到该类匹配的字符列表中。但是,如果/xx
模式修饰符生效,它们通常会被忽略,可以添加以提高可读性。它们不能添加到单个构造的中间
/ [ \x{10 FFFF} ] /xx # WRONG!
十六进制常量中间的空格是非法的。
要指定一个字面空格字符,可以使用反斜杠对其进行转义,例如
/[ a e i o u \ ]/xx
这将匹配英文元音加上空格字符。
为了清晰起见,您应该已经使用\t
来指定一个字面制表符,而\t
不受/xx
的影响。
匹配一系列字符并不罕见。幸运的是,无需列出范围内的所有字符,可以使用连字符 (-
)。如果在方括号字符类中,两个字符之间用连字符隔开,则会将其视为该类中包含这两个字符之间的所有字符。例如,[0-9]
匹配任何 ASCII 数字,而 [a-m]
匹配 ASCII 字母表前半部分的任何小写字母。
请注意,连字符两侧的两个字符不一定是字母或数字。任何字符都是可能的,虽然不建议这样做。['-?]
包含一系列字符,但大多数人不会知道这意味着哪些字符。此外,如果代码必须在使用不同字符集(如 EBCDIC)的平台上运行,则此类范围可能会导致可移植性问题。
如果字符类中的连字符在语法上不能是范围的一部分,例如因为它是在字符类的第一个或最后一个字符,或者它紧跟在范围之后,则连字符不是特殊的,因此被视为要匹配的字面字符。如果您希望字符集中的连字符被匹配,并且它在类中的位置使得它可以被视为范围的一部分,则必须使用反斜杠对其进行转义。
示例
[a-z] # Matches a character that is a lower case ASCII letter.
[a-fz] # Matches any letter between 'a' and 'f' (inclusive) or
# the letter 'z'.
[-z] # Matches either a hyphen ('-') or the letter 'z'.
[a-f-m] # Matches any letter between 'a' and 'f' (inclusive), the
# hyphen ('-'), or the letter 'm'.
['-?] # Matches any of the characters '()*+,-./0123456789:;<=>?
# (But not on an EBCDIC platform).
[\N{APOSTROPHE}-\N{QUESTION MARK}]
# Matches any of the characters '()*+,-./0123456789:;<=>?
# even on an EBCDIC platform.
[\N{U+27}-\N{U+3F}] # Same. (U+27 is "'", and U+3F is "?")
如上面最后两个示例所示,您可以通过使用 `\N{...}` 形式的范围端点来实现对非 ASCII 平台的可移植性。这些表示指定的范围应使用 Unicode 值进行解释,因此 `[\N{U+27}-\N{U+3F}]` 表示匹配 `\N{U+27}`、`\N{U+28}`、`\N{U+29}`,...,`\N{U+3D}`、`\N{U+3E}` 和 `\N{U+3F}`,无论这些的本机代码点版本是什么。这些被称为“Unicode”范围。如果任一端点采用 `\N{...}` 形式,则该范围被视为 Unicode 范围。如果另一个端点以非可移植方式指定,则在 `"use re 'strict'"` 下会发出 `regexp` 警告。
[\N{U+00}-\x09] # Warning under re 'strict'; \x09 is non-portable
[\N{U+00}-\t] # No warning;
以上两者都匹配字符 `\N{U+00}` `\N{U+01}`,... `\N{U+08}`、`\N{U+09}`,但 `\x09` 看起来像是错误,因此在 `re 'strict'` 下会发出警告。
Perl 还保证范围 `A-Z`、`a-z`、`0-9` 以及这些范围的任何子范围在任何平台上都匹配英语使用者所期望的匹配内容。也就是说,`[A-Z]` 匹配 26 个 ASCII 大写字母;`[a-z]` 匹配 26 个小写字母;`[0-9]` 匹配 10 个数字。子范围,如 `[h-k]`,相应地匹配,在这种情况下,只匹配四个字母 `“h”`、`“i”`、`“j”` 和 `“k”`。这是 ASCII 平台上的自然行为,其中 `“h”` 到 `“k”` 的代码点(序数值)是连续的整数(0x68 到 0x6B)。但在具有非 ASCII 本机字符集的平台上可能需要特殊处理才能实现这一点。例如,在 EBCDIC 平台上,`“h”` 的代码点是 0x88,`“i”` 是 0x89,`“j”` 是 0x91,`“k”` 是 0x92。Perl 特别处理 `[h-k]` 以排除间隙中的七个代码点:0x8A 到 0x90。只有当范围是 ASCII 大写字母、小写字母和数字范围的子范围,并且范围的每个端点都以字面量形式表示(如 `“A”`)或以命名字符形式表示(`\N{...}`,包括 `\N{U+...}` 形式)时,才会调用这种特殊处理。
EBCDIC 示例
[i-j] # Matches either "i" or "j"
[i-\N{LATIN SMALL LETTER J}] # Same
[i-\N{U+6A}] # Same
[\N{U+69}-\N{U+6A}] # Same
[\x{89}-\x{91}] # Matches 0x89 ("i"), 0x8A .. 0x90, 0x91 ("j")
[i-\x{91}] # Same
[\x{89}-j] # Same
[i-J] # Matches, 0x89 ("i") .. 0xC1 ("J"); special
# handling doesn't apply because range is mixed
# case
也可以列出您不想匹配的字符。您可以通过在字符类中使用插入符号 (^) 作为第一个字符来实现。例如,`[^a-z]` 匹配任何不是小写 ASCII 字母的字符,因此包括超过一百万个 Unicode 代码点。该类被称为“否定”或“反转”。
这种语法将脱字符号变成方括号字符类中的特殊字符,但前提是它必须是该类的第一个字符。因此,如果您希望脱字符号作为匹配的字符之一,请对脱字符号进行转义,或者不要将其放在首位。
在反转的方括号字符类中,Perl 会忽略通常情况下用于说明命名序列和某些字符在不区分大小写的 /i
匹配下应该匹配多个字符序列的 Unicode 规则。遵循这些规则可能会导致非常混乱的情况。
"ss" =~ /^[^\xDF]+$/ui; # Matches!
这应该匹配任何不属于 \xDF
或 \xDF
在 /i
下匹配的字符序列。"s"
不等于 \xDF
,但 Unicode 规定 "ss"
是 \xDF
在 /i
下匹配的内容。那么哪个“胜出”?由于字符串包含 ss
而导致匹配失败,还是由于包含 s
后面跟着另一个 s
而接受匹配?Perl 选择了后者。(请参阅上面 "方括号字符类" 中的说明。)
示例
"e" =~ /[^aeiou]/ # No match, the 'e' is listed.
"x" =~ /[^aeiou]/ # Match, as 'x' isn't a lowercase vowel.
"^" =~ /[^^]/ # No match, matches anything that isn't a caret.
"^" =~ /[x^]/ # Match, caret is not special here.
您可以在方括号字符类中放置任何反斜杠序列字符类(除了 \N
和 \R
),它将像您将反斜杠序列匹配的所有字符放在字符类中一样起作用。例如,[a-f\d]
匹配任何十进制数字或任何从 'a' 到 'f'(含)的字母。
方括号字符类中的 \N
必须采用 \N{name}
或 \N{U+hex char}
的形式,而不是匹配非换行符的形式,原因与点 .
在方括号字符类中失去其特殊含义相同:它匹配几乎所有内容,这通常不是您想要发生的事情。
示例
/[\p{Thai}\d]/ # Matches a character that is either a Thai
# character, or a digit.
/[^\p{Arabic}()]/ # Matches a character that is neither an Arabic
# character, nor a parenthesis.
反斜杠序列字符类不能构成范围的端点之一。因此,您不能说
/[\p{Thai}-\d]/ # Wrong!
POSIX 字符类采用 [:class:]
的形式,其中 class 是名称,[:
和 :]
是分隔符。POSIX 字符类仅出现在方括号字符类 内部,是列出字符组的一种方便且描述性的方法。
请注意语法,
# Correct:
$string =~ /[[:alpha:]]/
# Incorrect (will warn):
$string =~ /[:alpha:]/
后一种模式将是一个字符类,它包含冒号以及字母 a
、l
、p
和 h
。
POSIX 字符类可以是更大方括号字符类的一部分。例如,
[01[:alpha:]%]
是有效的,它匹配 '0'、'1'、任何字母字符和百分号。
Perl 识别以下 POSIX 字符类
alpha Any alphabetical character (e.g., [A-Za-z]).
alnum Any alphanumeric character (e.g., [A-Za-z0-9]).
ascii Any character in the ASCII character set.
blank A GNU extension, equal to a space or a horizontal tab ("\t").
cntrl Any control character. See Note [2] below.
digit Any decimal digit (e.g., [0-9]), equivalent to "\d".
graph Any printable character, excluding a space. See Note [3] below.
lower Any lowercase character (e.g., [a-z]).
print Any printable character, including a space. See Note [4] below.
punct Any graphical character excluding "word" characters. Note [5].
space Any whitespace character. "\s" including the vertical tab
("\cK").
upper Any uppercase character (e.g., [A-Z]).
word A Perl extension (e.g., [A-Za-z0-9_]), equivalent to "\w".
xdigit Any hexadecimal digit (e.g., [0-9a-fA-F]). Note [7].
与 Unicode 属性 一样,大多数 POSIX 属性匹配结果与是否启用不区分大小写 (/i
) 匹配无关。两个例外是 [:upper:]
和 [:lower:]
。在 /i
下,它们分别匹配 [:upper:]
和 [:lower:]
的并集。
大多数 POSIX 字符类有两个 Unicode 风格的 \p
属性对应物。(它们不是官方的 Unicode 属性,而是从官方 Unicode 属性派生的 Perl 扩展。)下表显示了 POSIX 字符类与这些对应物之间的关系。
一个对应物,在表中标注为“ASCII 范围 Unicode”的列中,只匹配 ASCII 字符集中的字符。
另一个对应物,在表中标注为“全范围 Unicode”的列中,匹配全 Unicode 字符集中所有合适的字符。例如,\p{Alpha}
不仅匹配 ASCII 字母字符,还匹配整个 Unicode 字符集中被认为是字母的任何字符。标注为“反斜杠序列”的列中的条目是一个(简短的)等价物。
[[:...:]] ASCII-range Full-range backslash Note
Unicode Unicode sequence
-----------------------------------------------------
alpha \p{PosixAlpha} \p{XPosixAlpha}
alnum \p{PosixAlnum} \p{XPosixAlnum}
ascii \p{ASCII}
blank \p{PosixBlank} \p{XPosixBlank} \h [1]
or \p{HorizSpace} [1]
cntrl \p{PosixCntrl} \p{XPosixCntrl} [2]
digit \p{PosixDigit} \p{XPosixDigit} \d
graph \p{PosixGraph} \p{XPosixGraph} [3]
lower \p{PosixLower} \p{XPosixLower}
print \p{PosixPrint} \p{XPosixPrint} [4]
punct \p{PosixPunct} \p{XPosixPunct} [5]
\p{PerlSpace} \p{XPerlSpace} \s [6]
space \p{PosixSpace} \p{XPosixSpace} [6]
upper \p{PosixUpper} \p{XPosixUpper}
word \p{PosixWord} \p{XPosixWord} \w
xdigit \p{PosixXDigit} \p{XPosixXDigit} [7]
\p{Blank}
和 \p{HorizSpace}
是同义词。
控制字符本身不产生输出,而是通常以某种方式控制终端:例如,换行符和退格符是控制字符。在 ASCII 平台上,在 ASCII 范围内,代码点在 0 到 31(含)之间的字符,加上 127 (DEL
) 是控制字符;在 EBCDIC 平台上,它们的对应物是控制字符。
任何图形字符,即可见字符。此类包含所有字母数字字符和所有标点符号字符。
所有可打印字符,即所有图形字符加上那些不是控制字符的空白字符。
\p{PosixPunct}
和 [[:punct:]]
在 ASCII 范围内匹配所有非控制字符、非字母数字字符、非空格字符:[-!"#$%&'()*+,./:;<=>?@[\\\]^_`{|}~]
(尽管如果生效了区域设置,它可能会改变 [[:punct:]]
的行为)。
同名属性 \p{Punct}
在 ASCII 范围内匹配略有不同的集合,即 [-!"#%&'()*,./:;?@[\\\]_{}]
。也就是说,它缺少九个字符 [$+<=>^`|~]
。这是因为 Unicode 将 POSIX 认为是标点符号的字符分为两类,标点符号和符号。
\p{XPosixPunct}
和(在 Unicode 规则下)[[:punct:]]
匹配 \p{PosixPunct}
在 ASCII 范围内匹配的内容,以及 \p{Punct}
匹配的内容。这与严格按照 \p{Punct}
匹配不同。换句话说,如果 Unicode 规则生效,[[:punct:]]
将匹配 Unicode 认为是标点符号的所有字符,以及 Unicode 认为是符号的所有 ASCII 范围字符。
从 Perl v5.18 开始,\p{XPerlSpace}
和 \p{Space}
的匹配结果完全相同。在早期版本中,它们的区别仅在于非本地匹配中,\p{XPerlSpace}
不匹配垂直制表符 \cK
。两个 ASCII 范围形式也是如此。
与 [[:digit:]]
匹配许多书写系统(如泰语和梵文)中的数字不同,目前只有两组十六进制数字,而且不太可能添加更多。这是因为您不仅需要十个数字,还需要六个 [A-F]
(和 [a-f]
)来对应。这意味着只有拉丁字母适合这些,而 Unicode 只有两组,熟悉的 ASCII 集,以及从 U+FF10(全角数字零)开始的全角形式。
除了表格中列出的名称外,还可以使用各种其他同义词。例如,\p{XPosixAlpha}
可以写成 \p{Alpha}
。所有这些都在 "perluniprops 中通过 \p{} 和 \P{} 访问的属性" 中列出。
\p
的对应项始终假设 Unicode 规则生效。在 ASCII 平台上,这意味着它们假设从 128 到 255 的代码点是 Latin-1,这意味着在本地规则下使用它们是不明智的,除非保证本地是 Latin-1 或 UTF-8。相反,POSIX 字符类在本地规则下很有用。它们受实际生效的规则影响,如下所示
应用哪些规则取决于 "perlre 中的“哪个字符集修饰符有效?”" 中所述。
Perl 对 POSIX 字符类的一个扩展是能够对其进行否定。这可以通过在类名前面加上一个插入符号 (^
) 来完成。一些例子
POSIX ASCII-range Full-range backslash
Unicode Unicode sequence
-----------------------------------------------------
[[:^digit:]] \P{PosixDigit} \P{XPosixDigit} \D
[[:^space:]] \P{PosixSpace} \P{XPosixSpace}
\P{PerlSpace} \P{XPerlSpace} \S
[[:^word:]] \P{PerlWord} \P{XPosixWord} \W
反斜杠序列可以表示 ASCII 或全范围 Unicode,具体取决于 "perlre 中的哪个字符集修饰符生效?" 中描述的各种因素。
Perl 识别 POSIX 字符类 [=class=]
和 [.class.]
,但(尚未)支持它们。任何尝试使用任一结构都会引发异常。
/[[:digit:]]/ # Matches a character that is a digit.
/[01[:lower:]]/ # Matches a character that is either a
# lowercase letter, or '0' or '1'.
/[[:digit:][:^xdigit:]]/ # Matches a character that can be anything
# except the letters 'a' to 'f' and 'A' to
# 'F'. This is because the main character
# class is composed of two POSIX character
# classes that are ORed together, one that
# matches any digit, and the other that
# matches anything that isn't a hex digit.
# The OR adds the digits, leaving only the
# letters 'a' to 'f' and 'A' to 'F' excluded.
这是一个花哨的方括号字符类,可用于更易读且不易出错的类,以及执行集合运算,例如交集。一个例子是
/(?[ \p{Thai} & \p{Digit} ])/
这将匹配泰国文字中的所有数字字符。
此功能在 Perl 5.18 中可用,作为实验性功能;在 5.36 中被接受。
use re 'strict
使用的规则适用于此结构。
我们可以扩展上面的例子
/(?[ ( \p{Thai} + \p{Lao} ) & \p{Digit} ])/
这匹配泰国或老挝文字中的数字。
请注意这些示例中的空格。此结构始终在其内部启用/xx
修饰符。
可用的二元运算符是
& intersection
+ union
| another name for '+', hence means union
- subtraction (the result matches the set consisting of those
code points matched by the first operand, excluding any that
are also matched by the second operand)
^ symmetric difference (the union minus the intersection). This
is like an exclusive or, in that the result is the set of code
points that are matched by either, but not both, of the
operands.
有一个一元运算符
! complement
所有二元运算符都左结合;"&"
优先级高于其他运算符,其他运算符的优先级相同。一元运算符右结合,优先级最高。因此,这遵循 Perl 逻辑运算符的正常优先级规则。使用括号来覆盖默认的优先级和结合性。
主要限制是所有内容都是元字符。因此,您不能通过以下方式引用单个字符
/(?[ a + b ])/ # Syntax error!
指定单个可键入字符的最简单方法是将其括在方括号中
/(?[ [a] + [b] ])/
(这与[ab]
相同。)您也可以说等效的
/(?[[ a b ]])/
(当然,您可以使用\x{...}
、\N{...}
等来指定单个字符。)
最后一个示例展示了使用此结构来指定普通方括号字符类而无需额外的集合运算。请注意其中的空格。这是允许的,因为/xx
在此结构中自动启用。
正常方括号字符类接受的所有其他转义符在这里也被接受。
由于此结构在use re 'strict
下编译,因此在正常类中生成警告的未识别转义符在这里是致命错误,以及来自这些类元素的所有其他警告,以及目前在re 'strict'
之外不会发出警告的一些做法。例如,您不能说
/(?[ [ \xF ] ])/ # Syntax error!
在无括号的\x
之后必须有两个十六进制数字(使用前导零以构成两个)。这些限制是为了降低因拼写错误导致类不匹配您预期结果的发生率。
如果一个正则方括号字符类包含\p{}
或\P{}
,并且与非 Unicode 代码点匹配,则可能会发出警告,因为结果未定义为 Unicode。使用此扩展形式时不会发出此类警告。
正则方括号字符类和这些类之间的最终区别在于,无法让这些类匹配多字符折叠。因此,
/(?[ [\xDF] ])/iu
不匹配字符串ss
。
您不必将 POSIX 类名称括在双括号内,因此以下两种方法都可行
/(?[ [:word:] - [:lower:] ])/
/(?[ [[:word:]] - [[:lower:]] ])/
任何包含的 POSIX 字符类,包括诸如 \w
和 \D
之类的,都遵守 /a
(和 /aa
)修饰符。
请注意,(?[ ])
是一个正则表达式编译时构造。任何尝试使用在包含的正则表达式编译时无法确定的内容都会导致致命错误。实际上,这仅意味着三个限制。
在 use locale
(或 /l
正则表达式修饰符)的范围内编译时,此构造假定执行时区域设置将是 UTF-8 区域设置,并且生成的模式始终使用 Unicode 规则。因此,匹配或不匹配不依赖于实际的运行时区域设置,因此不会启用污染。但是,如果运行时区域设置结果不是 UTF-8,则会引发 locale
类别警告。
使用的任何 用户定义属性 必须在编译正则表达式时已定义(但请注意,此构造可以代替此类属性)。
否则将使用 /d
规则编译的正则表达式,如果使用此构造,则将使用 /u
。因此,此构造告诉 Perl 您不希望对包含它的整个正则表达式使用 /d
规则。
请注意,跳过空格仅适用于此构造的内部。在构成初始 (?[
的任何字符之间,也不得有空格。在结束 ])
字符之间也不得有空格。
就像在所有正则表达式中一样,可以通过包含在正则表达式编译时插值的变量来构建模式。但目前,每个这样的子组件都应该是已编译的扩展括号字符类。
my $thai_or_lao = qr/(?[ \p{Thai} + \p{Lao} ])/;
...
qr/(?[ \p{Digit} & $thai_or_lao ])/;
如果您插值其他内容,模式可能仍然可以编译(或者可能死亡),但如果它编译了,它很可能不会像您预期的那样工作。
my $thai_or_lao = '\p{Thai} + \p{Lao}';
qr/(?[ \p{Digit} & $thai_or_lao ])/;
编译为
qr/(?[ \p{Digit} & \p{Thai} + \p{Lao} ])/;
这不会产生阅读源代码的人可能期望的效果,因为交集仅适用于 \p{Thai}
,排除了老挝语。
由于 Perl 解析事物的方式,您的括号和方括号可能需要平衡,甚至包括注释。如果您遇到任何示例,请将它们提交到 https://github.com/Perl/perl5/issues,以便我们为此手册页提供一个具体的示例。