2014-01-28 4 views
9

Разделение строки JavaScript на «символы» можно сделать тривиально, но есть проблемы, если вам небезразличен Юникод (и вы должны заботиться о Юникоде).Разделить строку JavaScript в массив кодовых точек? (с учетом «суррогатных пар», но не «графемных кластеров»)

JavaScript изначально обрабатывает символы как 16-битные объекты (UCS-2 or UTF-16), но это не позволяет использовать символы Unicode за пределами BMP (Basic Multilingual Plane).

Чтобы иметь дело с символами Unicode за пределами BMP, JavaScript должен учитывать «surrogate pairs», который он не делает изначально.

Я ищу, как разбить строку js на код, независимо от того, требуется ли кодовым точкам один или два символа JavaScript (единицы кода).

В зависимости от ваших потребностей, Расщепление codepoint не может быть достаточно, и вы можете разделить на «grapheme cluster», где кластер является базовым элементом кода следует все его без распорного модифицирующего кодовых, таких как combining accents and diacritics.

Для целей этого вопроса мне не требуется разделение кластерами графем.

ответ

8

@ ответ bobince имеет (к счастью) становится немного устаревшей; Теперь вы можете просто использовать

chrs = Array.from(text)

, чтобы получить список одной строки, которые элемент коды делают уважение астральный/32bit/суррогатные Unicode символов.

+0

Для современного решения итерации по строке с учетом суррогатных пар см. Https://stackoverflow.com/questions/1966476/javascript-process-each-letter-of-text/36392879#36392879 – hippietrail

2

В ECMAScript 6 вы можете использовать строку как итератор для получения кодовых точек, или вы можете искать строку для /./ug, или вы могли бы позвонить getCodePointAt(i) несколько раз.

К сожалению forof .. синтаксис и регулярное выражение флаги не могут быть 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) '. Аргумент, который он принимает, не является индексом codepoint, а индексом кодового блока (обычный индекс String). – glebm