属性类的两种维度
属性类把「字符集合」从手动枚举改成按属性引用:一类是通用类别(如 \p{L} 字母、\p{Nd} 十进制数字、\p{M} 组合标记),另一类是脚本或文字系统(如 \p{Han} 汉字、\p{Greek}、\p{Cyrillic})以及区块(如 \p{InCJK_Unified_Ideographs})。它们能显著提升可读性与覆盖面,但支持程度差异很大:PCRE、Java、.NET、JavaScript 的支持范围与写法各不相同,Go 与 Python 标准库只能用部分形式。使用前必须确认目标引擎的实际能力。
基本信息
| 通用类别 | \p{L} 字母、\p{Ll} 小写、\p{Nd} 数字、\p{M} 标记等 |
|---|---|
| 脚本属性 | \p{Han} 汉字、\p{Greek} 希腊文、\p{Cyrillic} 西里尔文 |
| 区块属性 | 按区块引用,如 \p{InBasic_Latin} 等写法因引擎而异 |
| 否定写法 | 大写 P 表示取反,如 \P{L} 表示非字母 |
| 引擎差异 | PCRE/Java/.NET 支持较全;JavaScript 需 u 标志;Go 与 Python 标准库受限 |
| 常见替代 | 不支持属性类时改用显式字符范围或以代码逻辑判断类别 |
典型使用场景
- 多语言校验:判断是否字母、数字、汉字,而不依赖 ASCII 假设
- 文本清洗:过滤组合标记、不可见格式字符或非目标脚本字符
- 结构化抽取:从混合文本中提取连续汉字或连续拉丁字母
- 安全过滤:以脚本白名单限制用户名可用文字范围
- 兼容旧引擎:确认目标环境支持程度,必要时退回显式范围写法
常见写法示例
常见写法示例
# 引擎支持属性类时(示意见各引擎文档):
# ^\p{L}+$ 仅字母(含汉字等其他字母类)
# \p{Han} 汉字
# ^\P{M}+$ 不含组合标记
# Python 标准库 re 不支持 \p{...},可用 unicodedata 判断类别
python -c "import unicodedata as u; print(u.category('中'), u.category('A'), u.category('1'))" # Lo Ll Nd
python -c "import re; print(bool(re.match(r'^[^\W\d_]+$', '中文abc', re.UNICODE)))" # 用 \w 反推字母
python -c "import re; print(re.findall(r'[\u4e00-\u9fff]+', 'abc 中文 def'))" # 显式范围匹配汉字常见属性写法
| 写法 | 含义 | 注意点 |
|---|---|---|
| \p{L} / \pL | 任意字母(含汉字) | 写法随引擎变化,部分引擎不支持简写形式 |
| \p{Ll} / \p{Lu} | 小写 / 大写字母 | 汉字属 Lo,不在此列 |
| \p{Nd} | 十进制数字 | 不等同于所有数字类,还有 No、Nl 子类 |
| \p{M} | 组合标记 | 文本清洗重点,删除会改变字形 |
| \p{Han} | 汉字脚本 | 部分引擎需写作 Script=Han |
| \P{...} | 取反 | 可用于排除特定类别或脚本 |
属性类的语义取决于引擎使用的 Unicode 数据版本:同一表达式在旧版引擎上可能不匹配新字符。跨系统校验必须固定双方使用的引擎与版本,或改用显式字符范围以换取确定性。
用属性类做安全过滤要格外小心:属性覆盖范围很广(例如 \p{L} 包含大量非拉丁字母与历史字符),用「属于某属性」当白名单可能放进不在预期内的字符。安全场景应结合字符白名单、归一化与长度限制。
JavaScript 需要 u 标志才启用 Unicode 相关能力,且早期只支持 \p{...} 的通用类别与脚本属性;Go 的 regexp 用 \p{...} 引用 Unicode 类别但不支持全部语法。具体支持列表以各引擎官方文档为准。