Come scoprire se una determinata stringa ha caratteri unicode (specialmente caratteri Double Byte)

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

  •  02-07-2019
  •  | 
  •  

Domanda

Per essere più precisi, devo sapere se (e se possibile, come) posso trovare se una determinata stringa ha caratteri a doppio byte o meno. Fondamentalmente, ho bisogno di aprire un pop-up per visualizzare un determinato testo che può contenere caratteri a doppio byte, come cinese o giapponese. In questo caso, abbiamo bisogno di regolare le dimensioni della finestra di quanto sarebbe per l'inglese o ASCII. Qualcuno ha un indizio?

È stato utile?

Soluzione

JavaScript contiene internamente il testo come UCS-2, che può codificare un sottoinsieme abbastanza esteso di Unicode.

Ma questo non è molto pertinente alla tua domanda. Una soluzione potrebbe essere quella di passare in rassegna la stringa ed esaminare i codici dei caratteri in ciascuna posizione:

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

Potrebbe non essere veloce come vorresti.

Altri suggerimenti

Ho usato la risposta di mikesamuel su questo. Tuttavia, a causa di questo modulo, ho notato che potrebbe esserci una sola barra di escape prima del u , ad es. \ u e non \\ u per farlo funzionare correttamente.

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

Funziona per me :)

Ho confrontato le due funzioni nelle risposte migliori e ho pensato di condividere i risultati. Ecco il codice di test che ho usato:

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

Durante l'esecuzione ho ottenuto:

isDoubleByte => 2421
containsNonLatinCodepoints => 868

Quindi per questa particolare stringa la soluzione regex è circa 3 volte più veloce.

Tuttavia, nota che per una stringa in cui il primo carattere è unicode, isDoubleByte () ritorna immediatamente e quindi è molto più veloce del regex (che ha ancora il sovraccarico dell'espressione regolare).

Ad esempio per la stringa ?? , ho ottenuto questi risultati:

isDoubleByte => 51
containsNonLatinCodepoints => 288

Per ottenere il meglio da entrambi, probabilmente è meglio combinare entrambi:

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

In tal caso, se il primo carattere è cinese (il che è probabile se l'intero testo è cinese), la funzione sarà veloce e tornerà immediatamente. In caso contrario, eseguirà la regex, che è ancora più veloce del controllo di ciascun personaggio singolarmente.

In realtà, tutti i personaggi sono Unicode, almeno dal punto di vista del motore Javascript.

Sfortunatamente, la semplice presenza di caratteri in un determinato intervallo Unicode non sarà sufficiente per determinare che è necessario più spazio. Esistono numerosi caratteri che occupano all'incirca la stessa quantità di spazio degli altri caratteri che hanno punti di codice Unicode ben al di sopra dell'intervallo ASCII. Virgolette tipografiche, caratteri con segni diacritici, alcuni simboli di punteggiatura e vari simboli di valuta sono al di fuori dell'intervallo ASCII basso e sono allocati in punti abbastanza disparati sul piano multilingue di base Unicode.

Generalmente, i progetti su cui ho lavorato scelgono di fornire spazio extra per tutte le lingue, o talvolta usano javascript per determinare se una finestra con attributi css della barra di scorrimento automatica ha effettivamente un contenuto con un'altezza che attiverebbe o meno una barra di scorrimento.

Se il rilevamento della presenza o del conteggio dei caratteri CJK sarà adeguato per determinare la necessità di un po 'di spazio extra, è possibile costruire una regex utilizzando i seguenti intervalli: [\ u3300- \ u9fff \ uf900- \ ufaff] e utilizzalo per estrarre un conteggio del numero di caratteri corrispondenti. (Questo è un po 'eccessivamente grossolano e manca tutti i casi non BMP, probabilmente esclude alcuni altri intervalli rilevanti e molto probabilmente include alcuni caratteri irrilevanti, ma è un punto di partenza).

Ancora una volta, sarai in grado di gestire solo un'euristica approssimativa senza qualcosa sulla falsariga di un motore di rendering di testo completo, perché quello che vuoi davvero è qualcosa come MeasureString di GDI (o qualsiasi altro equivalente del motore di rendering di testo). È passato un po 'di tempo da quando l'ho fatto, ma penso che l'equivalente HTML / DOM più vicino stia impostando una larghezza su un div e richiedendo l'altezza (taglia e incolla riutilizzi, quindi scusa se contiene errori):

o = document.getElementById("test");

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

Ecco il test di riferimento: http://jsben.ch/NKjKd

Questo è molto più veloce:

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

di questo:

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

Perché non lasciare che la finestra si ridimensioni automaticamente in base all'altezza / larghezza di runtime?

Esegui qualcosa del genere nel tuo pop-up:

window.resizeTo(document.body.clientWidth, document.body.clientHeight);
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top