Intl.Segmenter 是一个 JavaScript 对象,用于对文本进行区域设置敏感的分段。它可以帮助我们从字符串中提取有意义的项目,如单词、句子或字形。
最近看到一个拆分字符串的新方式,就是使用Intl.Segmenter将emoji字符串分割成字形的方法。
我以前都没用过这个Intl对象,现在我们一起来看看。
假设你想把用户输入拆分成句子,看起来是一个简单的 split() 任务...但这个问题有很多细微之处。
复制 'Hello! How are you?' .split ( / [ .! ?] / ) ;
// [ 'Hello' , ' How are you' , '' ]
使用 split() 会丢失定义的分隔符,并在所有地方包含这些空格。而且因为它依赖于硬编码的分隔符,所以对语言不敏感。
我不懂日语,但你会如何尝试将下面的字符串分割成单词或句子?
复制 // I am a cat. My name is Tanuki.
'吾輩は猫である。名前はたぬき。'
普通的字符串方法在这里是没有用的,但是Intl JavaScript API 确能解决这个问题。
Intl.Segmenter 来救场 Intl.Segmenter 是一个 JavaScript 对象,用于对文本进行区域设置敏感的分段。它可以帮助我们从字符串中提取有意义的项目,如单词、句子或字形。它的使用方式类似于其他的构造函数,可以使用 new 关键字来创建一个 Intl.Segmenter 对象。
复制 const segmenter = new Intl.Segmenter ( locale, { granularity: "word" } ) ;
在上面的代码中,locale 是字符串,表示要使用的区域设置。granularity 是字符串,表示分段的粒度。它可以是 "grapheme"(字形)、"word"(单词)或 "sentence"(句子)之一。
Intl.Segmenter 有一个很有用的方法叫做 segment(),它可以将文本拆分为有意义的段。
复制 const segments = segmenter.segment ( text ) ;
在上面的代码中,text 是要拆分的文本,segments 是返回的段的迭代器。你可以使用 for-of 循环来遍历段,或者使用 Array.from() 将它们转换为数组。
复制 const text = "Hello, world! How are you today?" ;
const segmenter = new Intl.Segmenter ( "en-US" , { granularity: "sentence" } ) ;
const segments = segmenter.segment ( text ) ;
for ( const segment of segments) {
console.log ( segment) ;
}
// Output:
// { index: 0 , value: "Hello, world!" , breakType: "" , breakIndex: 12 }
// { index: 13 , value: "How are you today?" , breakType: "" , breakIndex: 31 }
Intl.Segmenter 对象还有其他一些有用的方法,比如 breakType,用于检索分段的类型(例如,句子的末尾是否包含句号)。另一个有用的方法是 breakType,用于检索分段的类型。
例如:
复制 const text = "Hello, world! How are you today?" ;
const segmenter = new Intl.Segmenter ( "en-US" , { granularity: "sentence" } ) ;
const segments = segmenter.segment ( text ) ;
for ( const segment of segments) {
console.log ( segment.breakType ) ;
}
// Output:
// "exclamation"
// "question"
Intl.Segmenter 还有一个很有用的静态方法叫做 supportedLocalesOf(),它可以帮助你确定浏览器是否支持特定的区域设置。
复制 const supported = Intl.Segmenter .supportedLocalesOf ( [ "en-US" , "zh-CN" ] ) ;
console.log ( supported) ;
// Output:
// [ 'en-US' , 'zh-CN' ]
在上面的代码中,supported 数组包含浏览器支持的区域设置。
如果你想要对文本进行更细粒度的分段,你可以使用 Intl.ListFormat 对象。它可以帮助你将文本拆分为有意义的列表项。
使用方式类似于 Intl.Segmenter,你可以使用 new 关键字创建一个 Intl.ListFormat 对象。
复制 const listFormat = new Intl.ListFormat ( locale, { style: "long" , type: "conjunction" } ) ;
在上面的代码中,locale 是字符串,表示要使用的区域设置。style 和 type 是对象的属性,用于指定列表格式。style 可以是 "long" 或 "short",type 可以是 "conjunction"(并列)或 "disjunction"(或)。
Intl.ListFormat 有一个很有用的方法叫做 format(),它可以将数组转换为有意义的列表。
复制 const list = [ "apple" , "banana" , "orange" ] ;
const formatted = listFormat.format ( list) ;
console.log ( formatted) ;
// Output:
// "apple, banana, and orange"
在上面的代码中,formatted 是转换后的列表字符串。
Word 的颗粒度带有一个额外的isWordLike属性 如果把一个字符串分割成单词,所有的片段都包括空格和换行符。使用isWordLike属性将它们过滤掉。
复制 const segmenterDe = new Intl.Segmenter ( 'de' , {
granularity: 'word'
} ) ;
const segmentsDe = segmenterDe.segment ( 'Was geht ab?' ) ;
console.log ( [ ...segmentsDe] ) ;
// [
// { segment: 'Was' , index: 0 , input: 'Was geht ab?' , isWordLike: true } ,
// { segment: ' ' , index: 3 , input: 'Was geht ab?' , isWordLike: false } ,
// ...
// ]
console.log ( [ ...segmentsDe] .filter ( s => s.isWordLike ) ) ;
// [
// { segment: 'Was' , index: 0 , input: 'Was geht ab?' , isWordLike: true } ,
// { segment: 'geht' , index: 4 , input: 'Was geht ab?' , isWordLike: true } ,
// { segment: 'ab' , index: 9 , input: 'Was geht ab?' , isWordLike: true }
// ]
1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 上面通过isWordLike进行过滤会删除标点符号,如.、-、或?。
使用 Intl.Segmenter 来分割 emojis 如果你想把一个字符串分割成可视化的emojis,Intl.Segmenter也是一个很好的帮助。
复制 const emojis = '🫣🫵👨👨👦👦' ;
// ----
// Split by code units
console.log ( emojis.split ( '' ) ) ;
// [ '\uD83E' , '\uDEE3' , '\uD83E' , '\uDEF5' , '\uD83D' , '\uDE48' ]
// ----
// Split by code points
console.log ( [ ...emojis] ) ;
// [ '🫣' , '🫵' , '👨' , '' , '👨' , '' , '👦' , '' , '👦' ]
// ----
// Split by graphemes
const segmenter = new Intl.Segmenter ( 'en' , {
granularity: 'grapheme'
} ) ;
const segments = segmenter.segment ( emojis) ;
console.log ( Array.from (
segmenter.segment ( emojis) ,
s => s.segment
) ) ;
// [ '🫣' , '🫵' , '👨👨👦👦' ]
1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 请注意,字形也包括空格和 "正常 "字符。
编辑中可能存在的bug没法实时知道,事后为了解决这些bug,花了大量的时间进行log 调试,这边顺便给大家推荐一个好用的BUG监控工具 Fundebug。
参考 原文:https://www.stefanjudis.com/today-i-learned/how-to-split-javascript-strings-with-intl-segmenter/
最后 本文译自:https://marmelab.com/blog/2022/09/20/react-i-love-you.html