Unicode 字符多种多样,除去 ASCII 中的字母、数字、标点和中文字符,还包括其他多种语言和多种符号,有些符号甚至很难打出来(比如表示商标注册的™️),这时候该如何表示呢?再说远一点,如果我们想用一个字符组匹配所有的中文字符,能不能像[a-z]
那样呢?
使用正则表达式解决这类问题,必须依赖码值。前面讲过,每一个 Unicode 字符都有一个 Unicode 码值,所以在正则表达式的 Unicode 字符往往采用 Unicode 码值来指定。
一般来说,指定码值的形式有两种:\uxxxx和\u{xxxx}(其中的 xxxx 为编码的值,\u之后必须有4位十六进制数字)。.NET、Java、JavaScript 和 Python 使用前一种形式,而 PHP 和 Ruby 使用后一种形式(Ruby 1.9 以上版本才支持这种表示法,PHP 使用的字母是 x 而不是 u:\x{xxxx})
比如“发表”的“发”字对应的 Unicode 编码是 53 d1,所以可以在.NET、Java、JavaScript 的正则表达式中用\u53d1 表示它;Python 稍有不同,必须使用 u"\u53d1"(之前的 u 表示这是一个 Unicode 字符串);在 Ruby 中必须写作\u{53d1};在 PHP 中则写作\x{53d1}。
编码 | 语言 | 表示法 | 说明 |
---|---|---|---|
53 d1 | .NET | \u53d1 | |
Java | \u53d1 | ||
JavaScript | \u53d1 | ||
Python | \u53d1 | 必须使用 Unicode 字符串,在 Python 2 中, 要在字符串之前加 u 指定 Unicode 字符串 | |
PHP | \x{53d1} | 必须指定 Unicode 模式 | |
Ruby | \u{53d1} | 限 Ruby 1.9 以上版本,且必须显示指定 Unicode 模式 |
既然可以这样指定 Unicode 字符,自然也可以在字符组中用范围表示法指定一个 Unicode 编码范围了。这个功能,最常见的应用就是匹配任意一个中文字符。查询 Unicode 编码表可知,中文字符的编码点大多位于 4e00 到 9fff 之间,所以可以用这样的字符组匹配中文字符(Unicode 编码 4e00-9fff归类为** CJK 统一表意符号** CJK Unified Ideographs,涵盖了绝大多数中文字符)。
常用语言中匹配中文字符的字符组
语言 | 字符组 | 说明 |
---|---|---|
.NET | [\u4e00-\u9fff] | |
Java | [\u4e00-\u9fff] | |
JavaScript | [\u4e00-\u9fff] | |
Python | [\u4e00-\u9fff] | 必须使用 Unicode 字符串,在Python 2 中,要在字 符串之前加 u 指定 Unicode 字符串 |
PHP | [\x{4e00}-\x{9fff}] | 必须指定 Unicode 字符串 |
Ruby | [\u{4e00}-\u{9fff}] | 限 Ruby 1.9 以上版本 |
如果实在没有办法使用 Unicode 编码环境,而只能采用 GBK 编码,在 Python、Ruby 1.8 和 PHP 中,也有个办法匹配所有的中文字符;查阅 GBK 编码表可知,中文字符的 GBK 码值从 b0 00 开始,到 fa a0 结束,但是在通常情况下正则引擎无法正确识别非 Unicode 编码字符串的字符边界,所以不能写作[\xb000-\xfea0]
,只能写作[\xb0-\xfe][\x00-\xff]
,它匹配两个字节,第一个字节的码值范围从 b0 到 fe,第二个字节的码值范围从 00 到 ff,如果要匹配多个中文字符,必须添加括号将这两个字节分为一组,再使用量词,比如([\xb0-\xfe][\x00-\xff])+
。因为此时完全是将字符串作为单字节序列来对待的,所以也不应该指定任何与 Unicode 有关的设置(无论是正则表达式还是字符串,都是如此)。