要为额外的转义序列(\p{xx}、\P{xx} 和 \X)选择 UTF-8 模式,请使用“u”修饰符(参见 https://php.net/manual/en/reference.pcre.pattern.modifiers.php)。
我很好奇为什么德语的尖锐 S(ß)被 \p{Cc} 标记为控制字符,我花了一段时间才正确阅读第一句话:“从 5.1.0 开始,当选择 UTF-8 模式时,可以使用三种额外的转义序列来匹配通用字符类型。”:-$ 然后才发现如何做到这一点。
从 5.1.0 开始,当选择 _UTF-8 模式_ 时,可以使用三种额外的转义序列来匹配通用字符类型。它们是
上面由 xx
表示的属性名称仅限于 Unicode 通用类别属性。每个字符都只有一个这样的属性,由一个两位字母的缩写指定。为了与 Perl 保持兼容,否定可以通过在开括号和属性名称之间包含一个插入符号来指定。例如,\p{^Lu}
与 \P{Lu}
相同。
如果只用 \p
或 \P
指定一个字母,它将包括以该字母开头的所有属性。在这种情况下,在没有否定的情况下,转义序列中的花括号是可选的;这两个示例具有相同的效果
\p{L} \pL
属性 | 匹配 | 备注 |
---|---|---|
C |
其他 | |
Cc |
控制 | |
Cf |
格式 | |
Cn |
未分配 | |
Co |
专用使用 | |
Cs |
代理 | |
L |
字母 | 包括以下属性:Ll 、Lm 、Lo 、Lt 和 Lu 。 |
Ll |
小写字母 | |
Lm |
修饰字母 | |
Lo |
其他字母 | |
Lt |
标题大小写字母 | |
Lu |
大写字母 | |
M |
标记 | |
Mc |
间隔标记 | |
Me |
封闭标记 | |
Mn |
非间隔标记 | |
N |
数字 | |
Nd |
十进制数字 | |
Nl |
字母数字 | |
No |
其他数字 | |
P |
标点符号 | |
Pc |
连接标点符号 | |
Pd |
破折号标点符号 | |
Pe |
结束标点符号 | |
Pf |
最终标点符号 | |
Pi |
初始标点符号 | |
Po |
其他标点符号 | |
Ps |
开始标点符号 | |
S |
符号 | |
Sc |
货币符号 | |
Sk |
修饰符符号 | |
Sm |
数学符号 | |
So |
其他符号 | |
Z |
分隔符 | |
Zl |
换行符 | |
Zp |
段落分隔符 | |
Zs |
空格分隔符 |
PCRE 不支持 InMusicalSymbols
等扩展属性。
指定不区分大小写(不区分大小写)匹配不会影响这些转义序列。例如,\p{Lu}
始终只匹配大写字母。
Unicode 字符集被定义为属于某些脚本。可以使用脚本名称匹配来自这些集合之一的字符。例如
\p{Greek}
\P{Han}
那些不属于已识别脚本的字符被归类为 Common
。当前的脚本列表是
阿拉伯语 |
亚美尼亚语 |
阿维斯塔语 |
巴厘语 |
巴穆姆语 |
|
巴塔克语 |
孟加拉语 |
注音符号 |
婆罗米语 |
盲文 |
|
布吉语 |
布希德语 |
加拿大原住民 |
卡里亚语 |
恰克马语 |
|
占语 |
切罗基语 |
通用 |
科普特语 |
楔形文字 |
|
塞浦路斯语 |
西里尔语 |
德塞雷特语 |
天城体 |
埃及象形文字 |
|
埃塞俄比亚语 |
格鲁吉亚语 |
格拉哥里字母 |
哥特语 |
希腊语 |
|
古吉拉特语 |
旁遮普语 |
汉语 |
韩语 |
哈努诺语 |
|
希伯来语 |
平假名 |
帝国亚兰语 |
继承 |
铭文帕拉维语 |
|
铭文帕提亚语 |
爪哇语 |
凯西语 |
卡纳达语 |
片假名 |
|
卡雅李语 |
佉卢文 |
高棉语 |
老挝语 |
拉丁语 |
|
雷布查语 |
林布语 |
线形文字 B |
丽苏语 |
利西亚语 |
|
利底亚语 |
马拉雅拉姆语 |
曼达语 |
梅泰马耶克语 |
梅罗埃草书 |
|
梅罗埃象形文字 |
苗语 |
蒙古语 |
缅甸语 |
新泰卢语 |
|
恩科语 |
奥甘文字 |
古意大利语 |
古波斯语 |
古代南阿拉伯语 |
|
古代突厥语 |
奥尔奇基语 |
奥里亚语 |
奥斯曼尼亚语 |
八思巴文 |
|
腓尼基语 |
雷丈语 |
卢恩字母 |
撒马利亚语 |
索拉什特拉语 |
|
沙拉达语 |
萧氏字母 |
僧伽罗语 |
索拉索彭语 |
巽他语 |
|
西洛提·纳格里语 |
叙利亚语 |
他加禄语 |
塔班瓦语 |
泰勒语 |
|
泰喃语 |
泰越语 |
塔克里语 |
泰米尔语 |
泰卢固语 |
|
塔纳语 |
泰语 |
藏语 |
提菲纳格字母 |
乌加里特语 |
|
瓦伊语 |
彝语 |
\X
转义匹配 Unicode 扩展字形集群。扩展字形集群是一个或多个 Unicode 字符,它们组合在一起形成单个字形。实际上,这可以被认为是 .
的 Unicode 等效项,因为它将匹配一个组合字符,而不管实际用于呈现它的单个字符数量。
在早于 8.32 版本的 PCRE(对应于使用捆绑的 PCRE 库的 PHP 版本早于 5.4.14 版本)中,\X
等效于 (?>\PM\pM*)
。也就是说,它匹配一个没有“标记”属性的字符,后面跟着零个或多个具有“标记”属性的字符,并将该序列视为一个原子组(见下文)。具有“标记”属性的字符通常是影响前一个字符的重音符号。
通过 Unicode 属性匹配字符速度并不快,因为 PCRE 必须搜索包含超过一万五千个字符数据的结构。这就是为什么传统的转义序列(如 \d
和 \w
)在 PCRE 中不使用 Unicode 属性的原因。
要为额外的转义序列(\p{xx}、\P{xx} 和 \X)选择 UTF-8 模式,请使用“u”修饰符(参见 https://php.net/manual/en/reference.pcre.pattern.modifiers.php)。
我很好奇为什么德语的尖锐 S(ß)被 \p{Cc} 标记为控制字符,我花了一段时间才正确阅读第一句话:“从 5.1.0 开始,当选择 UTF-8 模式时,可以使用三种额外的转义序列来匹配通用字符类型。”:-$ 然后才发现如何做到这一点。
示例总是很有用!请参阅 https://unicodeplus.com/category 获取更多信息。
C 其他
Cc 控制(Unicode 代码点在范围 U+0000-U+001F 和 U+007F-U+009F 中)
Cf 格式(软连字符(U+00AD)、零宽度空格(U+200B)等)
Cn 未分配(Unicode 表中不存在的任何代码点)
Co 专用使用
Cs 代理(范围 U+D800 到 U+DFFF 中的字符,在 utf-8 中无效)
L 字母
Ll 小写字母(a-z、µßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿ 等等)
Lm 修饰字母(类似字母的字符,通常与其他字符组合,但在这里它们独立存在
ʰʱʲʳʴʵʶʷʸʹʺʻʼʽʾʿˀˁˆˇˈˉˊˋˌˍˎˏːˑˠˡˢˣˤˬˮʹͺՙ 等等)
Lo 其他字母(ªºƻǀǁǂǃʔ 和更多来自 unicase 字母的象形文字和字母)
Lt 标题大小写字母(DžLjNjDzᾈᾉᾊᾋᾌᾍᾎᾏᾘᾙᾚᾛᾜᾝᾞᾟᾨᾩᾪᾫᾬᾭᾮᾯᾼῌῼ)
Lu 大写字母(A-Z、ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞ 等等)
L& 普通字母(任何具有 Lu、Ll 或 Lt 属性的字符)
M 标记
Mc 间隔标记(拉丁字母中没有)
Me 封闭标记(组合封闭方块(U+20DE),如 a⃞ 中,组合封闭圆反斜杠(U+20E0),如 a⃠ 中)
Mn 非间隔标记(组合变音符号 U+0300-U+036f,例如此字母 a 上的重音符号:áâãāa̅ăȧäảåa̋ǎa̍a̎ȁa̐ȃ)
N 数字
Nd 十进制数字(0123456789、٠١٢٣٤٥٦٧٨٩ 和许多其他脚本中的数字。)
Nl 字母数字(ⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩⅪⅫⅬⅭⅮⅯⅰⅱⅲⅳⅴⅵⅶⅷⅸⅹⅺⅻⅼⅽⅾⅿ 和更多一些)
No 其他数字(⁰¹²³⁴⁵⁶⁷⁸⁹ ₀₁₂₃₄₅₆₇₈₉ ½⅓⅔¼¾⅕⅖⅗⅘⅙⅚⅐⅛⅜⅝⅞⅑⅒ ①②③④⑤⑥⑦⑧⑨⑩⑪⑫⑬⑭⑮⑯⑰⑱⑲⑳ 等等)
P 标点符号
Pc 连接标点符号(下划线(U+005F)、‿ 下连字 (U+203F)、⁀ 字元连接符 (U+2040) 等)
Pd 破折号标点符号(- 连字符 (U+002D)、‐ 短破折号 (U+2010)、‑ 不间断连字符 (U+2011)、‒ 数字破折号 (U+2012)、
– 短破折号 (U+2013)、— 长破折号 (U+2014)、― 横线 (U+2015) 等)
Pe 关闭标点符号(右括号、方括号或大括号:`)` (U+0029)、`]` (U+005D)、`}` (U+007D) 等)
Pf 结尾标点符号(右引号:» (U+00BB)、’ (U+2019)、” (U+201D) 等)
Pi 开始标点符号(左引号:« (U+00AB)、‘ (U+2018)、“ (U+201C) 等)
Po 其他标点符号 (!"#%&'*,./:;?@\¡§¶·¿)
Ps 打开标点符号(左括号、方括号或大括号:`(` (U+0028)、`[` (U+005B)、`{` (U+007B) 等)
S 符号
Sc 货币符号 ($¢£¤¥, ₠ ₡ ₢ ₣ ₤ ₥ ₦ ₧ ₨ ₩ ₪ ₫ € ₭ ₮ ₯ ₰ ₱ ₲ ₳ ₴ ₵ ₶ ₷ ₸ ₹ ₺ ₻ ₼ ₽ ₾ ₿ (U+20A0-U+20BF) 等)
Sk 修饰符号(通常与其他符号组合使用的符号类字符,但此处它们单独存在
^`¨¯´¸ 等等)
Sm 数学符号 (+<=>|~¬±×÷϶ 等等)
So 其他符号 (¦ 断线 (U+00A6)、© 版权符号 (U+00A9)、® 注册商标符号 (U+00AE)、° 度数符号 (U+00B0);
箭头、符号、表情符号等等)
Z 分隔符
Zl 行分隔符(行分隔符 (U+2028))
Zp 段落分隔符(段落分隔符 (U+2029))
Zs 空格分隔符(空格、不间断空格、全角空格、半角空格、字间空格、词间空格、数字空格、细空格、极细空格等)
我的国家,越南,有自己的字母表
http://en.wikipedia.org/wiki/Vietnamese_alphabet
我希望 PHP 在越南语方面能提供更好的支持。
对于那些想知道的人:'letter_titlecase' 应用于二合字/三合字,其中大写仅涉及第一个字母。
例如,Unicode 中的 "LJ" 二合字有三个代码点
(*) 大写 "LJ": U+01C7
(*) 标题大小写 "Lj": U+01C8
(*) 小写 "lj": U+01C9
页面顶部说明中没有明确说明,但这些转义字符类可以包含在方括号中,以构成更广泛的字符类。例如
<?php preg_match( '/[\p{N}\p{L}]+/', $data ) ?>
将匹配字母和数字的任何组合。
这些属性通常只有在 PCRE 使用 "--enable-unicode-properties" 编译时才可用
如果你想匹配任何单词,但又想提供一个备用方案,你可以这样做
<?php
if(@preg_match_all('/\p{L}+/u', $str, $arr) {
// 备用方案在这里
// 例如,对于不太精确的匹配,使用 '/\w+/u'
}
?>
如果你使用的是旧环境,你需要先检查 PCRE 版本是否支持上述 Unicode 指令
<?php
// 需要检查 PCRE 版本,因为一些环境
// 运行的是旧版本的 PCRE 库
//(在 *nix 环境中运行 `pcretest -C`)
$allowInternational = false;
if (defined('PCRE_VERSION')) {
if (intval(PCRE_VERSION) >= 7) { // 自 PHP 5.2.4 起可用常量
$allowInternational = true;
}
}
?>
现在,当 PCRE 库版本过旧或不可用时,你可以使用备用正则表达式(例如,使用 "/[a-z]/i")。
对于那些想知道的人:'letter_titlecase' 应用于二合字/三合字,其中大写仅涉及第一个字母。
例如,Unicode 中的 "LJ" 二合字有三个代码点
(*) 大写 "LJ": U+01C7
(*) 标题大小写 "Lj": U+01C8
(*) 小写 "lj": U+01C9
我发现预定义的 "supported" 脚本很有用,只是没有明确说明这些定义包含哪些 Unicode 字符范围。所以我写了这段代码来确定它们并打印出等效的 PCRE 字符类定义。输出片段示例如下(由于 PHP.net 帖子限制,我无法包含所有输出)
Canadian_Aboriginal=[\x{1400}-\x{167f}\x{18b0}-\x{18f5}]
程序
<?php
$scriptNames = array(
'阿拉伯语',
'亚美尼亚语',
'阿维斯塔语',
'巴厘语',
'巴穆姆语',
'巴塔克语',
'孟加拉语',
'注音符号',
'婆罗米文',
'盲文',
'布吉语',
'布希德语',
'加拿大原住民语言',
'卡里亚语',
'恰克玛语',
'占语',
'切罗基语',
'通用',
'科普特语',
'楔形文字',
'塞浦路斯语',
'西里尔字母',
'德塞雷特字母',
'天城体',
'埃及象形文字',
'埃塞俄比亚语',
'格鲁吉亚语',
'格拉哥里字母',
'哥特语',
'希腊语',
'古吉拉特语',
'旁遮普语',
'汉语',
'韩语',
'哈努诺语',
'希伯来语',
'平假名',
'帝国亚兰语',
'继承',
'铭文帕提亚语',
'铭文帕尔提语',
'爪哇语',
'凯西语',
'卡纳达语',
'片假名',
'克耶语',
'佉卢文',
'高棉语',
'老挝语',
'拉丁语',
'列普查语',
'林布语',
'线性B文',
'傈僳语',
'利西亚语',
'利底亚语',
'马拉雅拉姆语',
'曼达语',
'麦泰语',
'麦罗埃草书',
'麦罗埃象形文字',
'苗语',
'蒙古语',
'缅甸语',
'新泰卢语',
'恩科语',
'奥甘文',
'古意大利语',
'古波斯语',
'古南阿拉伯语',
'古突厥语',
'奥尔奇基语',
'奥里亚语',
'奥斯曼尼亚语',
'八思巴文',
'腓尼基语',
'雷藏语',
'卢恩字母',
'撒玛利亚语',
'索拉什特拉语',
'沙拉达文',
'肖文',
'僧伽罗语',
'索拉·索彭语',
'巽他语',
'西罗提·纳格里语',
'叙利亚语',
'他加禄语',
'塔班瓦语',
'泰语',
'傣文',
'傣维特语',
'塔克里语',
'泰米尔语',
'泰卢固语',
'塔纳语',
'泰国语',
'藏语',
'提菲纳格字母',
'乌加里特语',
'瓦伊语',
'彝语'
);
$scriptTypes = array();
foreach( $scriptNames as $n ) $scriptTypes[ $n ] = array();
for( $i=0; $i <= 0x10fff; $i++ ) {
//echo $i.PHP_EOL;
foreach( $scriptNames as $scriptName ) {
if ( preg_match( '/[\p{'. $scriptName .'}]/u', mb_chr( $i, 'UTF-8') ) ) {
if (empty( $scriptTypes[ $scriptName ])
|| ( ($i - $scriptTypes[ $scriptName ][ count( $scriptTypes[ $scriptName ] ) - 1 ][1]) > 1)
) {
$scriptTypes[ $scriptName ][] = [$i, $i];
} else {
$scriptTypes[ $scriptName ][ count( $scriptTypes[ $scriptName ] ) - 1 ][1] = $i;
}
}
}
}
foreach( $scriptTypes as $scriptName => $unicodeRanges ) {
printf(
'%s=[',
$scriptName
);
foreach( $unicodeRanges as $r ) {
printf(
'\x{%04x}',
$r[0]
);
if ($r[1] > $r[0] )
printf(
'-\x{%04x}',
$r[1]
);
}
printf(
']'.PHP_EOL
);
}