regex 总览待审核
字符的真面目 · 切分的三种粒度

分词与断行:把文本切成词 / 句,以及哪里能换行

字素簇那页把文本切成「一个个字符」,但切分不止这一种粒度。Intl.Segmenter 还能按 word(词)和 sentence(句)切;中文这种没有空格的文字也能切出词。另有一种独立粒度是 line breaking(UAX #14):哪里允许换行 —— 它和字素簇边界不是一回事(can't 中间能断字素簇却不该断行)。这一层 Intl.Segmenter 不提供,浏览器在排版时自己跑,我们用实测把它的结果显出来。

三种粒度:grapheme / word / sentence

同一段文本,选不同 granularity 切出的段完全不同。word 粒度下每段还带一个 isWordLike 标志,区分「真词」和「中间的空格 / 标点」(后者灰显):

中文分词:没有空格,靠词典 + 规则

英文用空格分词,"hello world" 一目了然;中文 "我爱自然语言处理" 没有任何分隔符,要切成词得靠词典 + 规则(和 拼音多音字选音同源)。Intl.Segmenter('zh', {granularity:'word'}) 直接给出浏览器内置的分词结果:

注意:分词结果因引擎而异(浏览器、Node、ICU 版本不同,词典就不同),它是「合理切法之一」而非唯一真理。需要可复现的分词,要锁定具体的分词库与词典版本。

断行(UAX #14):哪里能换行,字素簇边界管不着

把上面的盒子拖窄,文本会折行。能在哪里折由 UAX #14 的 line break 规则定:英文只在空格 / 连字符等机会处断,不会把 world 拆开;中文几乎每个字之间都能断。下面实测浏览器的真实折行 —— 每个被挤到新行行首的单位,左侧标一条红线(那就是一次实际换行):

220
一句话收束:切文本前先想清要哪种粒度 —— 数「字符」用 grapheme、取词 / 高亮用 word、摘要断句用 sentence、排版折行交给浏览器(UAX #14)。这些都是把「一长串 code point」按人类语言单位重新分组,和正则按字符类匹配是正交的两件事。中文分词的「一对多」不确定性,和 排序、拼音一样,本质是码点之外的语言知识。