前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
首页程序员面试题库JavaScript 正则 Unicode属性转义 \p{} 匹配
JavaScript数据处理

正则里的 \p{Script=Han} 是什么,怎么用它匹配汉字?

\p{…} 让正则按字符的 Unicode 属性来匹配,比如 \p{Script=Han} 匹配所有汉字,\p{Letter} 匹配任何语言的字母。它必须配合 u 标志(或 v 标志)使用,否则 \p 只会被当成字母 p。

前端进阶之旅 · 一题精讲更新于 2026.09.29
JavaScript#数据处理
先看核心答案读代码示例
理解线索

按属性匹配字符,而不是按码点区间

  1. 通用类别\p{Letter} 和 \p{Number} 这类,描述字符是字母、数字还是标点
  2. 脚本属性\p{Script=Han} 或 \p{Script=Latin} 这类,描述字符属于哪种文字
  3. \P{…}大写 P,匹配不具备该属性的字符

\p{…} 一次只判断一个码点。用户眼里的一个 emoji 可能由好几个码点拼成,属性转义切不准它,要用 Intl.Segmenter。

核心回答

先记住这个答案

Unicode 属性转义就是在正则里写 \p{属性},让引擎查 Unicode 数据库判断一个字符有没有这个属性。比如 \p{Script=Han} 匹配所有汉字,\p{Letter} 匹配任何语言的字母,\p{Number} 匹配各种数字,大写的 \P{…} 取反。它必须和 u 标志(ES2024 起也可以是 v 标志)一起用,否则 \p 会被当成普通字母 p,整条正则静默地匹配错东西。

  • \p{Script=Han} 匹配汉字,比手写 [一-龥] 覆盖更全
  • \p{Letter} 是所有语言的字母,中英文都算
  • 大写 \P{…} 表示取反
  • 不加 u 标志,\p{L} 只会匹配字面量 p{L}

从一段中英混排文本里提取字符

最常见的需求是从一段混排文本里挑出汉字、字母或数字。以前的写法是手写区间,比如 [一-龥],现在直接按属性写,意图也更清楚。

三种属性各匹配到什么JavaScript
const text = '订单Order-42号,价格¥99'

console.log(JSON.stringify(text.match(/\p{Script=Han}+/gu)))    // 只要汉字
console.log(JSON.stringify(text.match(/\p{Letter}+/gu)))        // 所有语言的字母
console.log(JSON.stringify(text.match(/\p{Decimal_Number}+/gu))) // 十进制数字
console.log(JSON.stringify(text.match(/\P{Letter}+/gu)))        // 取反:不是字母的
查看输出与解释
["订单","号","价格"]
["订单Order","号","价格"]
["42","99"]
["-42",",","¥99"]

第一行只挑汉字,所以 Order 被跳过了。第二行的 \p{Letter} 范围更宽,汉字在 Unicode 里也属于字母类别(Lo,即其他字母),所以「订单Order」连在一起成了一个匹配。这一点常被问到:想只要英文字母,要写 \p{Script=Latin},不能写 \p{Letter}。 第四行用大写 \P 取反,连字符、中文逗号、人民币符号和数字都被挑了出来。

为什么比手写 [一-龥] 靠谱

手写区间 [一-龥] 对应 U+4E00 到 U+9FA5,只覆盖了基本区里的一段汉字。像「𠮷」这种扩展区汉字,码点在 U+20BB7,远超这个区间,直接漏掉。再比如「〇」,它在 Unicode 里属于汉字脚本,但也不在这个区间。

\p{Script=Han} 不看码点落在哪里,而是查每个字符的属性表,扩展区、兼容区的汉字都能认出来。而且属性表跟着 Unicode 版本更新,新收录的字不用改正则。

扩展区汉字的对比
/[一-龥]/.test('𠮷') 返回 false,换成 /\p{Script=Han}/u.test('𠮷') 就返回 true。这里还有一个细节:「𠮷」在 JavaScript 字符串里占两个 UTF-16 单元(代理对),没有 u 标志时正则是按单元逐个看的,根本不知道这两个单元是一个字。u 标志让正则按码点工作,这也是 \p{…} 必须依赖它的原因之一。

不加 u 会发生什么

这是最容易掉的坑,因为它不报错。没有 u 标志时,为了兼容老代码,\p 是一个「无意义的转义」,等于字母 p,后面的 {L} 也被当成普通字符。

静默匹配错误
/\p{L}/.test('p{L}') 返回 true,而 /\p{L}/.test('a') 返回 false。也就是说,这条正则在找字面量「p{L}」,而不是字母。表单校验里写成这样,所有正常输入都会被判为不合法,排查时很难第一时间想到是少了一个标志。加上 u 之后,语法变严格,写错属性名(比如 \p{Hanzi})会直接抛 SyntaxError,反而更容易发现问题。
回答前,多想一步

容易答错的地方

以为 \p{Letter} 只匹配英文字母
\p{Letter} 是 Unicode 的通用类别,覆盖所有文字里的字母,汉字、日文假名、阿拉伯字母都算。只要拉丁字母,写 \p{Script=Latin};只要 ASCII 的 a 到 z,老老实实写 [a-zA-Z]。
把 Script 当成语言检测
\p{Script=Latin} 只能说明字符属于拉丁字母,英语、法语、越南语都用它。同理,\p{Script=Han} 也分不出中文和日文里的汉字。要识别语言得用专门的检测库,正则做不到。
以为属性转义能处理 emoji
\p{Emoji} 看着像能匹配 emoji,实际上数字 1 也带 Emoji 属性,/^\p{Emoji}$/u.test('1') 是 true。而一个家庭 emoji 由几个人像加零宽连接符组成,属性转义只能一个码点一个码点地看,切不出完整的一个。
试着用自己的话回答

面试官还会怎么问?

怎么校验用户名只能是中文、字母、数字和下划线?

如果只允许中文和 ASCII 字母数字,写成 /^[\p{Script=Han}a-zA-Z0-9_]+$/u。有人图省事写成 /^[\p{Letter}\p{Number}_]+$/u,这样俄文、希腊文、日文假名也都能通过,全角数字也算 \p{Number},要先确认业务能不能接受。

\p{Script} 和 \p{Script_Extensions} 有什么区别?

有些字符会被多种文字共用,比如中日文都用的句号「。」和顿号「、」。Script 只给每个字符一个归属,这类共用字符被归为 Common,所以 /\p{Script=Han}/u.test('。') 是 false。Script_Extensions(可简写为 scx)列出字符能出现在哪些文字里,/\p{scx=Han}/u.test('。') 就是 true。想连中文标点一起匹配时,用 scx 更合适。

怎么按用户看到的「一个字」来切分字符串?

用 Intl.Segmenter,粒度设成 grapheme,它按字素簇切分,组合 emoji、带变音符号的字母都会被当成一个整体。正则的 \p{…} 和 u 标志只能做到码点级别,比字素簇细。

从一道题,走向一组知识

把知识连起来

数据处理

分块解码时,TextDecoder 为什么要传 stream: true?

属性转义按码点判断字符,而流式解码要保证字节先被正确拼成码点,一个管识别一个管还原。

数据处理

字节不是合法 UTF-8 时,TextDecoder 会报错还是出乱码?

正则能匹配汉字的前提是字节已经解码正确,解码出错时得到的替换字符照样会混进匹配结果。

参考资料

  • JavaScript:数据处理参考资料

示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。

本题目录
  1. 先记住这个答案
  2. 从一段中英混排文本里提取字符
  3. 为什么比手写 [一-龥] 靠谱
  4. 不加 u 会发生什么
  5. 容易答错的地方
  6. 面试官还会怎么问
  7. 把知识连起来
读懂,再试着讲出来

先看核心答案,再读代码。最后展开追问,检查自己有没有遗漏边界。

试着回答追问
浏览全部面试题理解原理,也关注真实的使用场景。回到顶部 ↑