算法与数据结构 / regex · Unicode 字符模型与一个自研引擎 / 分词与断行:词、句与换行机会 待审核 16 / 36
字符的真面目 · 切分的三种粒度

分词与断行:词、句与换行机会

字素簇 那页把文本切成「一个个字符」,那是最细的一层人类语言单位。往上还有词与句:Intl.Segmentergranularitygrapheme 外还接受 wordsentence,中文这种词与词之间没有空格的文字也能切出词来。再往上是排版层的换行机会——哪里允许折行由 UAX #14 规定,granularity 没有对应取值(ECMA-402 只定义了那三个),浏览器排版时自己跑这套规则,只能用实测把结果显出来。

1 · 三种粒度

同一段文本选不同 granularity,切出的段完全不同。word 粒度下每段还带一个 isWordLike 标志,用来区分真正的词与夹在中间的空格、标点。sentence 粒度按句号、问号一类的终止符切,中英文混排时也能各按各的标点断开。

图 1-1 · 同一段文本在三种粒度下的切分结果,word 粒度里 isWordLike 为假的段灰显。可改文本、切换粒度与 locale。

2 · 中文分词

英文靠空格,hello world 一目了然。中文 我爱自然语言处理 没有任何分隔符,切词只能靠词典加规则,与 拼音 页里多音字选音是同一类问题:都是码点之外的语言知识。Intl.Segmenter 直接给出引擎内置词典的结果。

这套结果并非唯一正确解。北京大学生喝进口红酒 是分词教材里的经典歧义串,引擎切成「北京 / 大学生 / 喝 / 进口 / 红 / 酒」——它避开了「北京大学 / 生」这条错路,却把常见词 红酒 拆成了两个字;研究生命的起源 则切成「研究 / 生命 / 的 / 起源」,没有掉进「研究生」的坑。同一串文本在 Chrome 151 与 Node 26 上逐段一致,因为两者用的是同一套 ICU 词典(核对于 2026-08)。

图 2-1 · 四段无空格文本的分词结果,含两个经典歧义串。可点预设切换。

警示 · 分词结果随引擎与 ICU 版本变,它是合理切法之一,不是唯一真理。需要可复现的结果,就得锁定具体的分词库与词典版本,而不是依赖运行环境自带的那一份。

3 · 换行机会

换行是另一套规则。UAX #14 给每个码点标一个 line break class,再由规则表决定相邻两处是不是换行机会。字素簇边界处处都有,换行机会却稀疏得多:在一个 24 像素宽的盒子里实测,hellocan't 都占满一行不折——撇号两侧不构成机会;e-mail 折成 2 行,连字符之后是机会;stop—won 折成 3 行,破折号两侧都是;自然语言 折成 4 行,汉字之间处处可折(Chrome 151 实测,核对于 2026-08)。

图 3-1 · 文本按词(中文按字)切成单位后交给浏览器排版,实测哪些单位被挤到了新行行首,左侧标红线。可拖动盒子宽度或切换文本。

注 · 选粒度先看用途:数「字符」用字素簇,取词与高亮用 word,摘要断句用 sentence,排版折行交给浏览器。这几层都是把一长串 code point 按人类语言单位重新分组,与正则按字符类匹配是正交的两件事。中文分词的不确定性,和 排序 规则一样,都是写不进码点的语言知识。

4 · 参考文献

  1. Unicode. UAX #14: Unicode Line Breaking Algorithm. 换行机会的规范:line break class 的取值与规则表,本页第 3 节的实测现象照它解释。unicode.org
  2. Unicode. UAX #29: Unicode Text Segmentation. 词与句边界的规则(WB / SB 系列),Intl.Segmenterwordsentence 粒度即实现自它。unicode.org
  3. Ecma International. ECMA-402: Intl.Segmenter. granularity 的三个合法取值与 isWordLike 的定义,说明为何断行不在其列。tc39.es
  4. Unicode. UTS #35: LDML — Segmentations. CLDR 对 UAX #29 规则的 locale 定制层:segmentRulesexceptionssuppressionsdx(Dictionary Break Exclusion)等例外表即在此定义,是同一串文本随 locale 与版本变的出处。中日文分词所用的词典本身不在 LDML 里,属 ICU 的 brkitr 数据。unicode.org