为什么 Intl.Segmenter 在不同语言下会产生相同分段?
结论
Intl.Segmenter 的语言参数可能影响分段结果,但不保证不同语言或文本一定会产生不同边界。granularity 决定按字素、词或句子分段;语言参数则允许实现采用适合该语言的分段规则。对于主要由空格或标点分隔的文本,不同语言参数可能得到相同结果。
这段测试代码比较的是同一段文本在不同 lang 参数下,三种 granularity 的整组结果;它没有比较同一语言参数下三种粒度的结果。这样的比较可以检查不同 locale 的整组输出是否一致,但注释描述的比较对象不准确。
先确认代码比较的内容
getSegmentsAcrossLanguages(text) 返回的结构大致是:每个语言参数对应一个数组,数组中依次是 grapheme、word 和 sentence 三种粒度的结果。随后,代码比较相邻语言参数对应的整组结果。因此,它检查的是“这段文本在不同 locale 和三种粒度下的结果是否都一致”,而不是单独测试“语言参数是否影响 word 分段”。
要观察语言参数对分词的影响,可以固定文本和 granularity: "word",再逐一比较不同 locale。下面的代码会比较分段边界:
const text = "ประเทศไทยมีประชากรเกือบ 66 ล้านคน"
const locales = ["th", "en"]
const getWordSegments = (locale) => {
const segmenter = new Intl.Segmenter(locale, { granularity: "word" })
return Array.from(segmenter.segment(text), ({ segment, index, isWordLike }) => ({
segment,
index,
isWordLike
}))
}
for (const locale of locales) {
const segmenter = new Intl.Segmenter(locale, { granularity: "word" })
console.log(locale, segmenter.resolvedOptions().locale, getWordSegments(locale))
}
泰语文本不像英语那样用空格分隔每个词,适合用来观察词边界的处理方式。具体输出取决于运行环境使用的国际化数据和实现;单个浏览器的结果不能说明所有浏览器都必须产生相同或不同的边界。
检查 locale 是否被接受
可以先查看运行环境解析出的 locale,以及它是否支持请求的 locale:
const requestedLocale = "th"
const segmenter = new Intl.Segmenter(requestedLocale, { granularity: "word" })
console.log(segmenter.resolvedOptions())
console.log(Intl.Segmenter.supportedLocalesOf([requestedLocale]))
resolvedOptions().locale 显示实际解析出的 locale;supportedLocalesOf() 用于检查环境是否支持请求的 locale。这两项都不能证明某段文本一定会产生不同的分段结果。即使 locale 被接受,只要输入文本在相关规则下的边界相同,输出仍可能相同。
调整原有比较逻辑
如果只想检查同一文本、同一粒度下不同 locale 的分段是否一致,可以将粒度固定为 word,再比较 segment 和 index:
const getWordSegments = (text, locale) => {
const segmenter = new Intl.Segmenter(locale, { granularity: "word" })
return Array.from(segmenter.segment(text), ({ segment, index, isWordLike }) => ({
segment,
index,
isWordLike
}))
}
const text = "ประเทศไทยมีประชากรเกือบ 66 ล้านคน"
const results = langs.map(locale => ({
locale,
segments: getWordSegments(text, locale)
}))
console.log(results)
如果要像原逻辑那样比较 grapheme、word 和 sentence,应按粒度分别比较各 locale 的结果,避免把不同粒度的数据混在一起。JSON.stringify() 会对结果对象进行精确序列化比较。排查时,直接打印分段数组更容易看清边界、isWordLike 标记和实际解析出的 locale。
注意事项
Intl.Segmenter 负责分段,不会自动检测输入语言或翻译文本。指定语言参数是在请求相应 locale 的分段行为,最终结果也会受到实现和国际化数据的影响。要验证应用中的实际行为,应在目标运行环境中用需要处理的真实文本进行测试,并确保比较使用相同的文本和粒度。
备注:内容仅供参考。
