2014-01-28 7 views
9

Das Teilen einer JavaScript-Zeichenfolge in "Zeichen" kann trivial erfolgen, aber es gibt Probleme, wenn Unicode wichtig ist (und Sie sollten sich um Unicode kümmern).Split JavaScript Zeichenfolge in Array von Codepunkten? (unter Berücksichtigung von "Ersatzpaaren", aber nicht "Graphem-Clustern")

JavaScript behandelt native Zeichen als 16-Bit-Entities (UCS-2 or UTF-16), aber Unicode-Zeichen außerhalb der BMP (Basic Multilingual Plane) nicht zulässig.

Um mit Unicode-Zeichen jenseits der BMP umgehen zu können, muss JavaScript "surrogate pairs" berücksichtigen, was nativ nicht gemacht wird.

Ich bin auf der Suche nach einer js Zeichenfolge nach Codepunkt zu teilen, ob die Codepunkte ein oder zwei JavaScript "Zeichen" (Code-Einheiten) benötigen.

Je nach Bedarf, Spaltung von codepoint möglicherweise nicht genug sein, und man könnte durch „grapheme cluster“ geteilt werden soll, wo ein Cluster ein Basis-Codepunkt von allen seines nicht-Abstand Modifikator Codepoints, wie combining accents and diacritics gefolgt ist.

Für die Zwecke dieser Frage brauche ich keine Aufspaltung durch Graphem-Cluster.

Antwort

8

@ bobince Antwort hat (zum Glück) datiert etwas geworden; Sie können einfach jetzt

chrs = Array.from(text)

verwenden, um eine Liste von Single-Codepoint-Strings zu erhalten, die bezüglich tut Astral/32bit/Surrogat Unicode-Zeichen.

+0

Eine moderne Lösung zum Iterieren über einen String unter Berücksichtigung von Ersatzpaaren finden Sie unter: https://stackoverflow.com/questions/1966476/javascript-process-each-letter-of-text/36392879#36392879 – hippietrail

2

In ECMAScript 6 können Sie eine Zeichenfolge als Iterator verwenden, um Codepunkte zu erhalten, oder Sie können eine Zeichenfolge für /./ug suchen, oder Sie können getCodePointAt(i) wiederholt aufrufen.

Leider for .. of Syntax und regexp Flags können nicht polyfilled und Aufrufen einer polyfilled getCodePoint() wäre super langsam (O (n²)) werden, so dass wir diesen Ansatz nicht realistisch noch eine Weile nutzen.

So ist es die manuelle Art und Weise tun:

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; 
} 

Für die inverse dazu siehe https://stackoverflow.com/a/3759300/18936

+0

'getCodePointAt' ist' O (n) '. Das Argument, das akzeptiert wird, ist nicht der Codepunkt-Index, sondern der Code-Einheit-Index (der reguläre String-Index). – glebm