如何正确使用正则表达式匹配汉字

三日月綾香

English Version

tl;dr

[\u3006\u3007\u4e00-\u9fff\u3400-\u4dbf\U00020000-\U0002a6df\U0002a700-\U0002ebef\U00030000-\U0003134f]

解释

Python 示例

>>> import re
>>> han_regex = re.compile(r'[\u3006\u3007\u4e00-\u9fff\u3400-\u4dbf\U00020000-\U0002a6df\U0002a700-\U0002ebef\U00030000-\U0003134f]')
>>> is_han = lambda c: bool(han_regex.fullmatch(c))
>>> print([is_han(c) for c in 'm!文𦫖〇〆'])
[False, False, True, True, True, True]

JavaScript 示例

如果可以用 ES6 的 Unicode point escapes (\u{...}):

> const isHan = (c) => /^[\u3006\u3007\u4e00-\u9fff\u3400-\u4dbf\u{20000}-\u{2a6df}\u{2a700}-\u{2ebef}\u{30000}-\u{3134f}]$/u.test(c);
> console.log([...'m!文𦫖〇〆'].map(isHan));
[ false, false, true, true, true, true ]

如果不能用 ES6,就必须使用代理对

> const isHan = (c) => /^[\u3006\u3007\u4e00-\u9fff\u3400-\u4dbf]|[\ud840-\ud868\ud86a-\ud879\ud880-\ud883][\udc00-\udfff]|\ud869[\udc00-\udedf\udf00-\udfff]|\ud87a[\udc00-\udfef]|\ud884[\udc00-\udf4f]$/.test(c);
> console.log([...'m!文𦫖〇〆'].map(isHan));
[ false, false, true, true, true, true ]

为什么不能用 \p{sc=Han}

\p{...} 这种语法称为 Unicode property escapes。第一部分是 Unicode property name,sc 表示 script;第二部分 Han 是 Unicode property value。

要查看哪些字符属于 Han script,可以查看 UCD 中的 Scripts.txt

可以看出它不只包括汉字。

为什么不能用 \p{Ideo}

类似地,这里的 Ideo 是 Ideograph 的缩写。要查看哪些字符属于 Ideograph,可以查看 UCD 中的 PropList.txt

可以看出它不只包括汉字。