2014-01-28 43 views
9

將JavaScript字符串拆分爲「字符」可以輕鬆完成,但如果您關心Unicode(並且您應該關心Unicode),則會出現問題。將JavaScript字符串拆分成代碼點數組? (考慮到「替代對」而不是「字形串」)

JavaScript本身將字符視爲16位實體(UCS-2 or UTF-16),但這不允許BMP (Basic Multilingual Plane)之外的Unicode字符。

要處理BMP以外的Unicode字符,JavaScript必須考慮到「surrogate pairs」,它本身不會執行此操作。

我正在尋找如何通過代碼來分割js字符串,無論代碼點是否需要一個或兩個JavaScript「字符」(代碼單元)。

根據您的需求,通過codepoint分裂可能是不夠的,你可能想通過「grapheme cluster」,其中一個集羣是一個基礎碼點,隨後所有的無間距修改點,如combining accents and diacritics分裂。

爲了這個問題的目的,我不需要通過字素集羣來分割。

回答

8

@ bobince的回答有(幸運)成了有點過時;你現在可以簡單地使用

chrs = Array.from(text)

以獲得不尊重星體位/ 32位/代理Unicode字符單碼點的字符串列表。

+0

對於一個現代化的解決方案來迭代字符串,同時考慮代理對,請參閱:https://stackoverflow.com/questions/1966476/javascript-process-each-letter-of-text/36392879#36392879 – hippietrail

2

在ECMAScript 6中,您可以使用字符串作爲迭代器來獲取代碼點,或者您可以搜索字符串作爲/./ug,或者您可以重複調用getCodePointAt(i)

不幸的是for ... of語法和正則表達式標誌不能polyfilled和調用polyfilled getCodePoint()是超級慢(O(N²)),所以我們實際上不能夠使用這種方法了一段時間呢。

這樣做手工的方式:

String.prototype.toCodePoints= function() { 
    chars = []; 
    for (var i= 0; i<this.length; i++) { 
     var c1= this.charCodeAt(i); 
     if (c1>=0xD800 && c1<0xDC00 && i+1<this.length) { 
      var c2= this.charCodeAt(i+1); 
      if (c2>=0xDC00 && c2<0xE000) { 
       chars.push(0x10000 + ((c1-0xD800)<<10) + (c2-0xDC00)); 
       i++; 
       continue; 
      } 
     } 
     chars.push(c1); 
    } 
    return chars; 
} 

對於逆這一看https://stackoverflow.com/a/3759300/18936

+0

'getCodePointAt'是'O(n)'。它接受的參數不是代碼點索引,而是代碼單元索引(常規字符串索引)。 – glebm