40 Stimmen

Wie findet man heraus, ob eine bestimmte Zeichenkette Unicode-Zeichen enthält (insbesondere Double Byte-Zeichen)?

Um genauer zu sein, muss ich wissen, ob (und wenn möglich, wie) ich herausfinden kann, ob eine gegebene Zeichenkette Doppelbyte-Zeichen enthält oder nicht. Im Grunde muss ich ein Popup-Fenster öffnen, um einen bestimmten Text anzuzeigen, der Doppelbyte-Zeichen enthalten kann, wie z. B. Chinesisch oder Japanisch. In diesem Fall müssen wir die Fenstergröße anpassen, als es für Englisch oder ASCII der Fall wäre. Hat jemand einen Tipp?

0 Stimmen

Nun, ich hatte erwartet, dass das funktioniert. Aber es funktionierte nicht im IE. Ich vermute, dass es Layout-Probleme gibt. Wie auch immer, da der Code zum Berechnen der Länge und Höhe/Breite des anzuzeigenden Textes bereits vorhanden war, ging ich mit dem Code weiter, der nur herausfindet, ob ein Doppelbyte-Zeichen vorhanden ist oder nicht. Und das war die Lösung.

0 Stimmen

Mit HTML5 können Sie den Kontext eines Canvas-Elements ( var ctx = canvas.getContext('2d') ), um die Breite der Textmetrik zu erhalten. var text_width = ctx.measureText(text).width; Ich bin nicht sicher, wie gut diese Methode mit Unicode-Zeichen funktioniert, und es ist eine Schande, dass alle measureText Methode gibt derzeit die Breite zurück.

53voto

james Punkte 451

Ich habe die Antwort von mikesamuel in diesem Fall verwendet. Allerdings ist mir aufgefallen, dass vielleicht wegen dieser Form nur ein Escape-Schrägstrich vor dem u z.B. \u und nicht \\u damit dies korrekt funktioniert.

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

Funktioniert bei mir :)

3 Stimmen

Ihre Funktion ist viel besser als die angekreuzte Antwort, Regex ist immer besser

34voto

pcorcoran Punkte 7476

JavaScript speichert Text intern als UCS-2, das eine recht umfangreiche Untermenge von Unicode kodieren kann.

Aber das ist nicht wirklich relevant für Ihre Frage. Eine Lösung könnte darin bestehen, eine Schleife durch die Zeichenfolge zu ziehen und die Zeichencodes an jeder Position zu untersuchen:

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

Das geht vielleicht nicht so schnell, wie Sie es sich wünschen.

0 Stimmen

Ich kenne JavaScript nicht, aber meinen Sie nicht UTF-16? So etwas wie UCS-16 gibt es nicht; in der ISO/IEC 10646-Norm, die dem Unicode entspricht, gab es UCS-x-Kodierungsformen, die inzwischen veraltet sind. UCS-2 verwendete genau zwei Bytes und konnte somit die ersten 2^16 Unicode-Zeichen darstellen. UTF-16 hingegen verwendet 16-Bit-Einheiten, aber nicht unbedingt ein einziges davon. Alle Unicode-Zeichen können als UTF-16-Bytefolgen dargestellt werden.

16voto

laurent Punkte 83238

Ich habe die beiden Funktionen in den oberen Antworten verglichen und dachte, ich würde die Ergebnisse mitteilen. Hier ist der von mir verwendete Testcode:

const text1 = `The Chinese Wikipedia was established along with 12 other Wikipedias in May 2001. 178518501839`;

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

Wenn ich dies ausführe, erhalte ich:

isDoubleByte => 2421
containsNonLatinCodepoints => 868

Für diese spezielle Zeichenfolge ist die Regex-Lösung also etwa 3 Mal schneller.

Beachten Sie jedoch, dass bei einer Zeichenkette, bei der das erste Zeichen ein Unicode-Zeichen ist, isDoubleByte() sofort zurück und ist daher viel schneller als der Regex (der immer noch den Overhead des regulären Ausdrucks hat).

Zum Beispiel für die Zeichenkette erhielt ich diese Ergebnisse:

isDoubleByte => 51
containsNonLatinCodepoints => 288

Um das Beste aus beiden Welten zu bekommen, ist es wahrscheinlich besser, beides zu kombinieren:

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

Wenn in diesem Fall das erste Zeichen Chinesisch ist (was wahrscheinlich ist, wenn der gesamte Text Chinesisch ist), ist die Funktion schnell und kehrt sofort zurück. Ist dies nicht der Fall, wird der Regex ausgeführt, was immer noch schneller ist als die Überprüfung jedes einzelnen Zeichens.

7voto

David Dehghan Punkte 17766

Hier ist ein Benchmark-Test: http://jsben.ch/NKjKd

Das ist viel schneller:

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

als dies:

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

0 Stimmen

Unglaublich! Vielen Dank! Es half bei der Herstellung einer Krypto-Bibliothek Natrium frei

2 Stimmen

@jolly Natriumfrei?

6voto

JasonTrue Punkte 18756

Eigentlich sind alle Zeichen Unicode, zumindest aus Sicht der Javascript-Engine.

Leider reicht das bloße Vorhandensein von Zeichen in einem bestimmten Unicode-Bereich nicht aus, um festzustellen, dass Sie mehr Platz benötigen. Es gibt eine Reihe von Zeichen, die ungefähr die gleiche Menge an Platz beanspruchen wie andere Zeichen, deren Unicode-Codepunkte weit über dem ASCII-Bereich liegen. Typografische Anführungszeichen, Zeichen mit diakritischen Zeichen, bestimmte Interpunktionssymbole und verschiedene Währungssymbole liegen außerhalb des niedrigen ASCII-Bereichs und werden auf der Unicode-Basisebene für mehrere Sprachen an ganz unterschiedlichen Stellen zugeordnet.

In der Regel entscheiden sich die Projekte, an denen ich gearbeitet habe, dafür, zusätzlichen Platz für alle Sprachen zur Verfügung zu stellen, oder verwenden manchmal Javascript, um festzustellen, ob ein Fenster mit css-Attributen für die automatische Bildlaufleiste tatsächlich einen Inhalt mit einer Höhe hat, die eine Bildlaufleiste auslösen würde oder nicht.

Wenn die Erkennung des Vorhandenseins oder der Anzahl von CJK-Zeichen ausreicht, um festzustellen, dass Sie ein wenig mehr Platz benötigen, können Sie eine Regex mit den folgenden Bereichen erstellen: [ \u3300 - \u9fff\uf900 - \ufaff ], und verwenden Sie diese, um die Anzahl der übereinstimmenden Zeichen zu extrahieren. (Dies ist ein wenig zu grob und lässt alle Nicht-BMP-Fälle aus, schließt wahrscheinlich einige andere relevante Bereiche aus und enthält höchstwahrscheinlich einige irrelevante Zeichen, aber es ist ein Ausgangspunkt).

Auch hier werden Sie nur in der Lage sein, eine grobe Heuristik ohne etwas in der Art einer vollständigen Text-Rendering-Engine zu verwalten, denn was Sie wirklich wollen, ist etwas wie GDI's MeasureString (oder jede andere Text-Rendering-Engine-Äquivalent). Es ist eine Weile her, seit ich das getan habe, aber ich denke, das nächste HTML/DOM-Äquivalent ist die Einstellung einer Breite auf ein div und die Höhe anfordern (Ausschneiden und Einfügen Wiederverwendung, so Entschuldigungen, wenn dies Fehler enthält):

o = document.getElementById("test");

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

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X