40 votes

Les chaînes de caractères JavaScript à l'extérieur de la BMP

BMP en cours de Plan Multilingue de Base

Selon JavaScript: les Bonnes Parties:

JavaScript a été construit à une époque où l'Unicode est un jeu de caractères 16 bits, donc tous les caractères en JavaScript sont de 16 bits de large.

Cela me mène à croire que le JavaScript utilise UCS-2 (pas en UTF-16!) et ne peut gérer que les caractères U+FFFF.

Complément d'enquête le confirme:

> String.fromCharCode(0x20001);

L' fromCharCode méthode semble être la seule à utiliser le plus bas de 16 bits lors de la restitution de caractère Unicode. Essayer d'obtenir U+20001 (CJK unifiée ideograph 20001) au lieu de cela renvoie U+0001.

Question: est-il possible de gérer l'après-BMP caractères en JavaScript?


2011-07-31: faites glisser les douze de Support de l'Unicode Shootout: le Bon, Le Mauvais, & (pour la plupart) Laid couvre les problèmes liés à cela très bien:

dLwbz.png

35voto

bobince Points 270740

Dépend de ce que tu veux dire par "soutien". Vous pouvez certainement mettre la non-UCS-2 personnages dans un JS chaîne à l'aide de substituts, et les navigateurs afficheront eux s'ils le peuvent.

Mais, chaque élément dans un JS chaîne est séparée de code UTF-16 de l'unité. Il n'y a pas de langue de niveau de soutien pour le traitement complet de caractères: tous les membres de type Chaîne (length, split, slice etc), le contact avec les unités de code pas de caractères, il en sera très heureux de split paires de substitution ou de détenir des invalides de substitution séquences.

Si vous voulez que la mère porteuse-connaissance des méthodes, je crains que vous allez avoir à commencer à écrire vous-même! Par exemple:

String.prototype.getCodePointLength= function() {
    return this.length-this.split(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g).length+1;
};

String.fromCodePoint= function() {
    var chars= Array.prototype.slice.call(arguments);
    for (var i= chars.length; i-->0;) {
        var n = chars[i]-0x10000;
        if (n>=0)
            chars.splice(i, 1, 0xD800+(n>>10), 0xDC00+(n&0x3FF));
    }
    return String.fromCharCode.apply(null, chars);
};

2voto

ecellingsworth Points 21

Je suis venu à la même conclusion que bobince. Si vous souhaitez travailler avec des chaînes de caractères contenant des caractères unicode à l'extérieur de la BMP, vous avez ré-écrire du javascript Chaîne de méthodes. C'est parce que javascript compte des caractères comme chaque code 16 bits de valeur. Des symboles à l'extérieur de la BMP besoin de deux valeurs de code à être représentés. Vous courrez dans un cas où certains symboles comptent comme deux personnages et certains comptent qu'un.

J'ai ré-implémenté les méthodes suivantes pour traiter chaque point de code unicode comme un seul caractère: .longueur, .charCodeAt, .fromCharCode, .charAt, .indexOf, .lastIndexOf, .splice, et .split.

Vous pouvez le vérifier sur jsfiddle: http://jsfiddle.net/Y89Du/

Voici le code sans commentaires. Je l'ai testé, mais il peut encore y avoir des erreurs. Les commentaires sont les bienvenus.

if (!String.prototype.ucLength) {
    String.prototype.ucLength = function() {
        // this solution was taken from 
        // http://stackoverflow.com/questions/3744721/javascript-strings-outside-of-the-bmp
        return this.length - this.split(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g).length + 1;
    };
}

if (!String.prototype.codePointAt) {
    String.prototype.codePointAt = function (ucPos) {
        if (isNaN(ucPos)){
            ucPos = 0;
        }
        var str = String(this);
        var codePoint = null;
        var pairFound = false;
        var ucIndex = -1;
        var i = 0;  
        while (i < str.length){
            ucIndex += 1;
            var code = str.charCodeAt(i);
            var next = str.charCodeAt(i + 1);
            pairFound = (0xD800 <= code && code <= 0xDBFF && 0xDC00 <= next && next <= 0xDFFF);
            if (ucIndex == ucPos){
                codePoint = pairFound ? ((code - 0xD800) * 0x400) + (next - 0xDC00) + 0x10000 : code;
                break;
            } else{
                i += pairFound ? 2 : 1;
            }
        }
        return codePoint;
    };
}

if (!String.fromCodePoint) {
    String.fromCodePoint = function () {
        var strChars = [], codePoint, offset, codeValues, i;
        for (i = 0; i < arguments.length; ++i) {
            codePoint = arguments[i];
            offset = codePoint - 0x10000;
            if (codePoint > 0xFFFF){
                codeValues = [0xD800 + (offset >> 10), 0xDC00 + (offset & 0x3FF)];
            } else{
                codeValues = [codePoint];
            }
            strChars.push(String.fromCharCode.apply(null, codeValues));
        }
        return strChars.join("");
    };
}

if (!String.prototype.ucCharAt) {
    String.prototype.ucCharAt = function (ucIndex) {
        var str = String(this);
        var codePoint = str.codePointAt(ucIndex);
        var ucChar = String.fromCodePoint(codePoint);
        return ucChar;
    };
}

if (!String.prototype.ucIndexOf) {
    String.prototype.ucIndexOf = function (searchStr, ucStart) {
        if (isNaN(ucStart)){
            ucStart = 0;
        }
        if (ucStart < 0){
            ucStart = 0;
        }
        var str = String(this);
        var strUCLength = str.ucLength();
        searchStr = String(searchStr);
        var ucSearchLength = searchStr.ucLength();
        var i = ucStart;
        while (i < strUCLength){
            var ucSlice = str.ucSlice(i,i+ucSearchLength);
            if (ucSlice == searchStr){
                return i;
            }
            i++;
        }
        return -1;
    };
}

if (!String.prototype.ucLastIndexOf) {
    String.prototype.ucLastIndexOf = function (searchStr, ucStart) {
        var str = String(this);
        var strUCLength = str.ucLength();
        if (isNaN(ucStart)){
            ucStart = strUCLength - 1;
        }
        if (ucStart >= strUCLength){
            ucStart = strUCLength - 1;
        }
        searchStr = String(searchStr);
        var ucSearchLength = searchStr.ucLength();
        var i = ucStart;
        while (i >= 0){
            var ucSlice = str.ucSlice(i,i+ucSearchLength);
            if (ucSlice == searchStr){
                return i;
            }
            i--;
        }
        return -1;
    };
}

if (!String.prototype.ucSlice) {
    String.prototype.ucSlice = function (ucStart, ucStop) {
        var str = String(this);
        var strUCLength = str.ucLength();
        if (isNaN(ucStart)){
            ucStart = 0;
        }
        if (ucStart < 0){
            ucStart = strUCLength + ucStart;
            if (ucStart < 0){ ucStart = 0;}
        }
        if (typeof(ucStop) == 'undefined'){
            ucStop = strUCLength - 1;
        }
        if (ucStop < 0){
            ucStop = strUCLength + ucStop;
            if (ucStop < 0){ ucStop = 0;}
        }
        var ucChars = [];
        var i = ucStart;
        while (i < ucStop){
            ucChars.push(str.ucCharAt(i));
            i++;
        }
        return ucChars.join("");
    };
}

if (!String.prototype.ucSplit) {
    String.prototype.ucSplit = function (delimeter, limit) {
        var str = String(this);
        var strUCLength = str.ucLength();
        var ucChars = [];
        if (delimeter == ''){
            for (var i = 0; i < strUCLength; i++){
                ucChars.push(str.ucCharAt(i));
            }
            ucChars = ucChars.slice(0, 0 + limit);
        } else{
            ucChars = str.split(delimeter, limit);
        }
        return ucChars;
    };
}

0voto

Jukka K. Korpela Points 71599

Oui, vous le pouvez. Bien que le soutien à la non-BMP caractères directement dans les documents source est facultatif en fonction du standard ECMAScript, les navigateurs modernes vous permettent de les utiliser. Naturellement, l'encodage du document doit être déclarée, et pour la plupart des cas, vous devrez utiliser le codage UTF-8. En outre, vous avez besoin d'un éditeur qui peut gérer l'UTF-8, et que vous avez besoin de méthode d'entrée(s); voir, par exemple, mon Unicode Complète de l'Entrée de l'utilité.

En utilisant les outils appropriés et les paramètres, vous pouvez écrire var foo = '

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X