Comment savoir si une chaîne particulière contient des caractères Unicode (en particulier des caractères double octet)

StackOverflow https://stackoverflow.com/questions/147824

  •  02-07-2019
  •  | 
  •  

Question

Pour être plus précis, j'ai besoin de savoir si (et si possible, comment) je peux trouver si une chaîne donnée contient des caractères à double octet ou non. Fondamentalement, je dois ouvrir une fenêtre contextuelle pour afficher un texte donné pouvant contenir des caractères à double octet, tels que le chinois ou le japonais. Dans ce cas, nous devons ajuster la taille de la fenêtre par rapport à l'anglais ou à l'ASCII. Quelqu'un a un indice?

Était-ce utile?

La solution

JavaScript contient le texte en interne sous le nom UCS-2, qui peut coder un sous-ensemble assez étendu d'Unicode.

Mais cela n’est pas vraiment lié à votre question. Une solution pourrait consister à parcourir la chaîne et à examiner les codes de caractère à chaque position:

function isDoubleByte(str) {
    for (var i = 0, n = str.length; i < n; i++) {
        if (str.charCodeAt( i ) > 255) { return true; }
    }
    return false;
}

Cela risque de ne pas être aussi rapide que vous le souhaitez.

Autres conseils

J'ai utilisé la réponse de mikesamuel sur celui-ci. Cependant, j’ai remarqué que, à cause de cette forme, il ne devrait y avoir qu’une barre oblique d'échappement avant u , par exemple. \ u et non pas \\ u pour que cela fonctionne correctement.

function containsNonLatinCodepoints(s) {
    return /[^\u0000-\u00ff]/.test(s);
}

Fonctionne pour moi:)

J'ai comparé les deux fonctions dans les réponses principales et j'ai pensé partager les résultats. Voici le code de test que j'ai utilisé:

const text1 = `The Chinese Wikipedia was established along with 12 other Wikipedias in May 2001. 中文維基百科的副標題是「海納百川,有容乃大」,這是中国的清朝政治家林则徐(1785年-1850年)於1839年為`;

const regex = /[^\u0000-\u00ff]/; // Small performance gain from pre-compiling the regex
function containsNonLatinCodepoints(s) {
    return regex.test(s);
}

function isDoubleByte(str) {
    for (var i = 0, n = str.length; i < n; i++) {
        if (str.charCodeAt( i ) > 255) { return true; }
    }
    return false;
}

function benchmark(fn, str) {
    let startTime = new Date();
    for (let i = 0; i < 10000000; i++) {
        fn(str);
    }   
    let endTime = new Date();

    return endTime.getTime() - startTime.getTime();
}

console.info('isDoubleByte => ' + benchmark(isDoubleByte, text1));
console.info('containsNonLatinCodepoints => ' + benchmark(containsNonLatinCodepoints, text1));

Quand je lance ceci, j'ai:

isDoubleByte => 2421
containsNonLatinCodepoints => 868

Donc, pour cette chaîne particulière, la solution regex est environ 3 fois plus rapide.

Toutefois, notez que pour une chaîne dont le premier caractère est unicode, isDoubleByte () est renvoyé immédiatement et est donc beaucoup plus rapide que l'expression régulière (qui a toujours le surcoût de l'expression régulière).

Par exemple, pour la chaîne ?? , j'ai obtenu les résultats suivants:

isDoubleByte => 51
containsNonLatinCodepoints => 288

Pour tirer le meilleur des deux mondes, il est probablement préférable de combiner les deux:

var regex = /[^\u0000-\u00ff]/; // Small performance gain from pre-compiling the regex
function containsDoubleByte(str) {
    if (!str.length) return false;
    if (str.charCodeAt(0) > 255) return true;
    return regex.test(str);
}

Dans ce cas, si le premier caractère est le chinois (ce qui est probable si tout le texte est chinois), la fonction sera rapide et reviendra immédiatement. Sinon, la regex sera exécutée, ce qui est plus rapide que de vérifier chaque caractère individuellement.

En fait, tous les caractères sont en Unicode, du moins du point de vue du moteur Javascript.

Malheureusement, la simple présence de caractères dans une plage Unicode particulière ne sera pas suffisante pour déterminer que vous avez besoin de plus d'espace. Un certain nombre de caractères occupent à peu près la même quantité d’espace que d’autres caractères dotés de points de code Unicode bien supérieurs à la plage ASCII. Les guillemets typographiques, les caractères avec des signes diacritiques, certains symboles de ponctuation et divers symboles monétaires se situent en dehors de la plage ASCII basse et sont alloués à des emplacements assez disparates sur le plan multilingue de base Unicode.

En général, les projets sur lesquels j'ai travaillé choisissent de fournir un espace supplémentaire pour toutes les langues, ou utilisent parfois le javascript pour déterminer si une fenêtre avec des attributs css auto-scrollbar a réellement un contenu avec une hauteur qui déclencherait ou non une barre de défilement.

Si la détection de la présence ou du nombre de caractères CJK est suffisante pour déterminer que vous avez besoin d'un peu d'espace supplémentaire, vous pouvez créer une expression régulière à l'aide des plages suivantes: [\ u3300- \ u9fff \ uf900- \ ufaff], et utilisez-le pour extraire le nombre de caractères qui correspondent. (Ceci est un peu trop grossier, et omet tous les cas non BMP, exclut probablement d'autres plages pertinentes et inclut très probablement des caractères non pertinents, mais c'est un point de départ).

Encore une fois, vous ne pourrez gérer qu'une heuristique approximative sans avoir recours à un moteur de rendu de texte intégral, car vous voulez vraiment quelque chose comme MeasureString de GDI (ou tout autre équivalent du moteur de rendu de texte). Cela fait longtemps que je ne l’ai pas fait, mais je pense que l’équivalent HTML / DOM le plus proche consiste à définir une largeur sur une div et à demander la hauteur (copier-coller, réutiliser, donc des excuses si cela contient des erreurs):

o = document.getElementById("test");

document.defaultView.getComputedStyle(o,"").getPropertyValue("height"))

Voici le test d'évaluation: http://jsben.ch/NKjKd

C'est beaucoup plus rapide:

function containsNonLatinCodepoints(s) {
    return /[^\u0000-\u00ff]/.test(s);
}

que cela:

function isDoubleByte(str) {
    for (var i = 0, n = str.length; i < n; i++) {
        if (str.charCodeAt( i ) > 255) { return true; }
    }
    return false;
}

Pourquoi ne pas laisser la fenêtre se redimensionner en fonction de la hauteur / largeur d'exécution?

Exécutez quelque chose comme ceci dans votre fenêtre contextuelle:

window.resizeTo(document.body.clientWidth, document.body.clientHeight);
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top