# 10 正则匹配汉字

在此之前，项目中使用正则匹配汉字的表达式都是 `/[\u4e00-\u9fa5]/`，虽然常用，但是一直未深究其所以然。

## 汉文与汉字

首先，我们需要了解**汉文**和**汉字**这两个基础概念：

* \*\*汉文（Han Script）\*\*是汉语、日本语、朝鲜语、韩国语的书写系统中的一种文字；
* \*\*汉字（CJK Ideograph）\*\*是汉文的基本单元。

汉字文化圈中的许多国家或地区都对汉字提出了自己的编码标准，而 Unicode 将这些标准加总在一起进行统一编码，力求实现原标准与 Unicode 编码之间的无损转换。

## 字符集和字符编码

Unicode，GBK 和 UTF-8 有什么区别？很多人总是将它们混淆在一起，傻傻分不清，实际上它们不是同领域的概念。

### 字符集

我们常见的 Unicode、 ASCII 是一种字符集（character set），其作用是用一系列数字来表示字符（character），这些数字有时也称为码点（code points）。

例如 ASCII 码是美国制定了一套字符编码，ASCII 码使用一个字节来表示一个字符，一共规定了 128 个字符的编码，对应英语字符与二进制位之间的关系。

但对于一些亚洲国家的文字，比如中文，这些符号远远不够，必须使用多个字节表示一个符号。比如简体中文的 GB2312 编码方式，使用两个字节表示一个字符，最多可以表示 256 x 256 = 65536 个符号。

由于世界上存在着多种编码方式，同一个二进制数字可以被解释成不同的符号。如果用错误的编码方式解读一段文本，就会出现乱码。由此 Unicode 应运而生。

Unicode 是一个统一编码集合，类似于世界语，它将世界上所有符号都赋予了一个第一无二的编码。由于每个字符的编码都是唯一的，这样避免了字符编码混乱的问题。

### 字符编码

有了字符集，我们现在可以用任意数字来表示现实中的字符了。需要注意的是 Unicode 只是一个符号集，它只规定了符号的二进制代码，却没有规定这个二进制代码应该如何存储。所以字符要保存在计算机中，必须要先经过编码。

UTF-8 是 Unicode 的字符编码方式之一，同时也是互联网上使用最广的一种 Unicode 的实现方式。它规定了 Unicode 符号的存储方式。UTF-8 最大的一个特点，就是它是一种变长的编码方式。它可以使用 1\~4 个字节表示一个符号，根据不同的符号而变化字节长度。

GBK（汉字内码扩展规范）和 UTF-8 类似，是一种中文字符编码方式。

总结：**ASCII 和 Unicode 是一种字符集，而 UTF-8 和 GBK 是一种字符编码方式**。两者不是一类事物, 是无法进行对比的。

## 正则匹配汉字

介绍完字符集和字符编码之后，回到正题，我们已经知道「汉字」是汉文的基本单元，但这里的「汉字」具体指代哪些字符集呢？

Unicode 从语义（semantic）、抽象字形（abstract shape），具体字形（typeface）三个维度出发，把不同编码标准里「起源相同、本义相同、形状一样或稍异」的汉字赋予相同编码，这些被编码的字符称为中日韩统一表意文字，即我们上面所提到的「汉字」。如果把它们全部列举出来写成正则表达式，那么就是技术上完整的匹配汉字的正则表达式了。

我们一开始所提到的正则表达式 `/[\u4e00-\u9fa5]/` 匹配区域对应的是 Unicode 1.0.1 就收录进来的中日韩统一表意文字区块，在 Unicode 3.0 以前，这个正则表达式确实给出了所有汉字的编码。换言之，从 1992 年到 1999 年，这个正则表达式确实是正确的，想必这个表达式已经有 20 年了。

然而时光飞逝，Unicode 在 2017 年 6 月发布了 10.0.0 版本。在这 20 年间，Unicode 添加了许多汉字。这些新增的汉字并不在上面这个正则表达式匹配的区域中，所以我们的正则也需要与时俱进匹配最新的 Unicode 标准。

而这个问题的标准答案正则即是：

```javascript
const HanZi = /\p{Unified_Ideograph}/u
```

* `\u`是 ECMAScript 2015 定义的正则表达式标志，意味着将表达式作为 Unicode 码点序列；
* `\p`是 ECMAScript 2018 定义的正则表达式 Unicode 属性转义，它赋予了我们根据 Unicode 字符的属性数据构造表达式的能力；
* `Unified_Ideograph` 是 Unicode 字符的一个二值属性，对于汉字，其取值为 Yes，否则为 No。

因此 `\p{Unified_Ideograph}` 匹配所有满足 `Unified_Ideograph=yes` 的 Unicode 字符，而它的底层实现由运行时所依赖的 Unicode 版本决定，开发者不需要知道汉字的具体 Unicode 码点范围。

## 兼容性

Chrome 64 以上以及 Safari 11.1 以上都支持正则表达式 Unicode 属性转义。对于其他浏览器，推荐使用 7.7 版本的 `@babel/env` 转译配置将带有属性转义的正则表达式转为 Unicode 码点正则表达式。

```
{
  "presets": ["@babel/env"]
}
```

参考文章： [JavaScript 正则表达式匹配汉字](https://zhuanlan.zhihu.com/p/33335629)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://chanshiyu.gitbook.io/blog/qian-duan/javascript/10-zheng-ze-pi-pei-han-zi.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
