Come posso elaborare ogni lettera di testo usando Javascript?


363

Vorrei avvisare ogni singola lettera di una stringa, ma non sono sicuro di come farlo.

Quindi, se ho:

var str = 'This is my string';

Vorrei poter avvisare separatamente T, h, i, s, ecc. Questo è solo l'inizio di un'idea su cui sto lavorando, ma devo sapere come elaborare ciascuna lettera separatamente.

Voglio usare jQuery e stavo pensando che potrei aver bisogno di usare la funzione split dopo aver testato la lunghezza della stringa.

Idee?


3
Forse stavi cercando questo: a partire da ES6, c'è for(const c of str) { ... }. Più di questo più avanti in una risposta abbastanza dettagliata ma non sufficientemente votata. PS: il link di @ ARJUN non funziona per me.
Max

Risposte:


421

Se l'ordine degli avvisi è importante, utilizzare questo:

for (var i = 0; i < str.length; i++) {
  alert(str.charAt(i));
}

Se l'ordine degli avvisi non ha importanza, utilizzare questo:

var i = str.length;
while (i--) {
  alert(str.charAt(i));
}


2
l'utilizzo di []per ottenere il carattere in una posizione specifica non è supportato in IE <9
vsync

13
come spiegato nell'altra risposta, è possibile utilizzare str.charAt (i) al posto di []. per ulteriori informazioni sul motivo per cui dovresti usare charAt vs [], vedi string.charAt (x) o string [x]
Julian Soro,

12
Trovo difficile credere che qualsiasi moderno compilatore JS ricalcoli la lunghezza se la stringa non è stata modificata all'interno del loop. In ogni altra lingua farei felicemente il controllo della lunghezza nella clausola test del ciclo for, supponendo che il compilatore lo sappia meglio e lo ottimizzerei di conseguenza.
Echelon,

3
@Dagmar: Javascript non utilizza UTF-8, utilizza UTF-16 (o UCS-2, a seconda del browser). Ogni singolo carattere può essere rappresentato come UTF-8 o UTF-16 ma non presenta questo problema. Gli unici che hanno il problema sono quelli che richiedono quattro byte in UTF-16 anziché due byte. 💩 è un carattere che richiede quattro byte in UTF-16. I termini chiave per cercare maggiori informazioni sono "piano astrale", "non BMP" e "coppia surrogata".
hippietrail,

1
@Dagmar: Java e Javascript hanno entrambi UTF-16 (precedentemente UCS-) in comune. La terza piattaforma principale che la utilizza è Windows. I protocolli Unix, MacOS e Internet utilizzano UTF-8. charAtè rimasto dai giorni UCS-2 quando non c'erano coppie surrogate e per risolvere il problema è codepointAtstata aggiunta una nuova funzione a JavaScript che gestisce correttamente la nostra amichevole pila di cacca. Credo che anche Java ce l'abbia.
hippietrail,

240

Probabilmente è più che risolto. Voglio solo contribuire con un'altra soluzione semplice:

var text = 'uololooo';

// With ES6
[...text].forEach(c => console.log(c))

// With the `of` operator
for (const c of text) {
    console.log(c)
}

// With ES5
for (var x = 0, c=''; c = text.charAt(x); x++) { 
    console.log(c); 
}

// ES5 without the for loop:
text.split('').forEach(function(c) {
    console.log(c);
});

4
l'ultimo esempio può essere semplicemente[...text].forEach(console.log)
Govind Rai

10
No, non può. forEach()passa l'indice e l'array come secondo e terzo argomento. Preferirei non registrarlo ...
Mr. Goferito

1
Si noti che sia l'operatore spread (primo esempio) che la chiamata split (ultimo esempio) creeranno un nuovo array. Questo di solito non sarà un problema, ma potrebbe essere costoso per stringhe di grandi dimensioni o usi frequenti.
Randolpho,

Che direfor (let c of [...text]) { console.log(c) }
Flimm,

Con ciò crei un nuovo array dalla stringa. Non vedo il vantaggio. let c of textfa già il lavoro.
Mr. Goferito,

73

Una possibile soluzione in javascript puro:

for (var x = 0; x < str.length; x++)
{
    var c = str.charAt(x);
    alert(c);
}

Probabilmente sarebbe meglio con var x = 0 e var c = str.charAt (x).
Rich

2
Inoltre, str.length dovrebbe essere memorizzato in una variabile in modo da non dover continuare ad accedere.
Eli Gray,

8
@EliGrey È davvero così importante mettere la lunghezza in una variabile? Hai dei benchmark quando sarebbe preferibile avere meno righe di codice?
pm_labs

@paul_sns È interessante notare che sembra esserci una differenza minore , almeno in Edge (differenza di 0,7 ms per un array di 10000 elementi): jsfiddle.net/carcigenicate/v8vvjoc1/1 . Probabilmente non è un test perfetto, ma si basa su una media di 10000 test.
Carcigenicate

1
@paul_sns È interessante notare che Chrome ha fatto lo stesso test in circa il 2% delle volte (~ 5ms contro ~ 0,0997ms), ed entrambe le versioni hanno dato lo stesso tempo, quindi Edge non è ottimizzato.
Carcigenicate

69

Come elaborare ogni lettera di testo (con parametri di riferimento)

https://jsperf.com/str-for-in-of-foreach-map-2

per

Classico e di gran lunga quello con le massime prestazioni . Dovresti andare con questo se hai intenzione di usarlo in un algoritmo critico per le prestazioni o se richiede la massima compatibilità con le versioni del browser.

for (var i = 0; i < str.length; i++) {
  console.info(str[i]);
}

per ... di

per ... of è il nuovo ES6 per iteratore. Supportato dalla maggior parte dei browser moderni. È visivamente più accattivante ed è meno soggetto a errori di battitura. Se stai cercando questo in un'applicazione di produzione, dovresti probabilmente usare un transpiler come Babel .

let result = '';
for (let letter of str) {
  result += letter;
}

per ciascuno

Approccio funzionale . Approvato Airbnb . Il più grande svantaggio di farlo in questo modo è il split(), che crea un nuovo array per memorizzare ogni singola lettera della stringa.

Perché? Questo rafforza la nostra regola immutabile. Trattare con funzioni pure che restituiscono valori è più facile da ragionare rispetto agli effetti collaterali.

// ES6 version.
let result = '';
str.split('').forEach(letter => {
  result += letter;
});

o

var result = '';
str.split('').forEach(function(letter) {
  result += letter;
});

Quelli che seguono sono quelli che non mi piacciono.

per ... in

A differenza di ... of, ottieni l'indice delle lettere anziché la lettera. Si comporta abbastanza male.

var result = '';
for (var letterIndex in str) {
  result += str[letterIndex];
}

carta geografica

Approccio funzionale, che è buono. Tuttavia, la mappa non è pensata per essere utilizzata per questo. Dovrebbe essere usato quando è necessario modificare i valori all'interno di un array, che non è il caso.

// ES6 version.
var result = '';
str.split('').map(letter => {
  result += letter;
});

o

let result = '';
str.split('').map(function(letter) {
  result += letter;
});

1
Sulla mia macchina il forloop classico era in realtà il secondo più lento, mentre for...ofera il più veloce (circa tre volte più veloce for).
John Montgomery,

1
Dov'è il benchmark? Qual è la soluzione più veloce?
poitroae,

1
@johnywhy È successo due anni fa e il link è morto, quindi non sono sicuro di come ti aspetti che io difenda il risultato che ho ricevuto allora. La creazione di un nuovo benchmark ora concorda con la conclusione di zurfyx, con il forloop leggermente più veloce.
John Montgomery,

1
@JohnMontgomery Non mi aspetto che tu faccia nulla. Solo una nota per i futuri lettori che i tuoi risultati sono diversi dalla risposta. Personalmente vorrei sapere quali risultati si applicano ai browser oggi 2020, anche se il 2018 non era tanto tempo fa. Quale link è morto?
johny perché

1
@johnywhy Il link in alto con tutti i test effettivi sta restituendo un 404 per me.
John Montgomery,

42

La maggior parte se non tutte le risposte qui sono sbagliate perché si romperanno ogni volta che c'è un carattere nella stringa all'esterno del BMP Unicode (Basic Multilingual Plane) . Ciò significa che tutte le Emoji saranno rotte .

JavaScript utilizza Unicode UTF- 16 per tutte le stringhe. In UTF-16, i personaggi oltre il BMP sono composti da due parti, chiamate " Coppia surrogata " " e la maggior parte delle risposte qui elaborerà ciascuna parte di tali coppie singolarmente invece che come un singolo carattere.

Un modo nel JavaScript moderno almeno dal 2016 è utilizzare il nuovo iteratore di stringhe . Ecco l'esempio (quasi) direttamente da MDN:

var string = 'A\uD835\uDC68B\uD835\uDC69C\uD835\uDC6A';

for (var v of string) {
  alert(v);
}
// "A"
// "\uD835\uDC68"
// "B"
// "\uD835\uDC69"
// "C"
// "\uD835\uDC6A"


4
Per una soluzione moderna per dividere una stringa in caratteri tenendo conto coppie di surrogati, vedi: stackoverflow.com/a/42596897/527702
hippietrail

20

Puoi provare questo

var arrValues = 'This is my string'.split('');
// Loop over each value in the array.
$.each(arrValues, function (intIndex, objValue) {
    alert(objValue);
})

11
È ancora un'opzione, ma non performante. Non mettere jQuery ovunque.
cagatay,

10

Un'altra soluzione ...

var strg= 'This is my string';
for(indx in strg){
  alert(strg[indx]);
}

3
Se vuoi solo il carattere e non l'indice, sarebbe più veloce usare un for..ofciclofor (let ch of t) { alert(ch) }
Shaheen Ghiassy,

10

Quando devo scrivere un codice breve o una riga, uso questo "hack":

'Hello World'.replace(/./g, function (char) {
    alert(char);
    return char; // this is optional 
});

Questo non conterà le nuove righe, quindi può essere una cosa positiva o negativa. Se si desidera includere newline, sostituire: /./con /[\S\s]/. Gli altri one-liner che potresti vedere probabilmente usano .split()che hanno molti problemi


migliore risposta. Tiene conto dei problemi con Unicode e può anche essere usato con costrutti funzionali con .map () ecc.
Rofrol

L'unica cosa che non mi piace di questo è quando voglio accedere ai parametri extra passati alla forEachfunzione della chiamata rispetto ai parametri inviatireplace . Se so che sto ASCIIing, penso di avere ancora alcuni casi d'uso per split. Ottima risposta, però!
ruffin,

Questa risposta ha il vantaggio di preselezionare i valori da verificare comunque
Fuzzyma

1
Pensavo che questo non avrebbe tenuto conto dei problemi Unicode a meno che non avesse la ubandiera insieme alla gbandiera? OK appena testato e avevo ragione.
hippietrail,

9

Il nuovo JS consente questo:

const str = 'This is my string';
Array.from(str).forEach(alert);

8

È meglio usare l'istruzione for ... of, se la stringa contiene caratteri unicode, a causa della diversa dimensione dei byte.

for(var c of "tree 木") { console.log(c); }
//"𝐀A".length === 3

7

risposta breve: Array.from(string)ti darà ciò che probabilmente desideri e quindi puoi iterare su di esso o qualsiasi altra cosa poiché è solo un array.

ok proviamo con questa stringa: abc|⚫️\n⚪️|👨‍👩‍👧‍👧.

i punti di codice sono:

97
98
99
124
9899, 65039
10
9898, 65039
124
128104, 8205, 128105, 8205, 128103, 8205, 128103

quindi alcuni caratteri hanno un punto di codice (byte) e alcuni ne hanno due o più e una nuova riga aggiunta per ulteriori test.

quindi dopo il test ci sono due modi:

  • byte per byte (punto di codice per punto di codice)
  • gruppi di personaggi (ma non l'intera emoji della famiglia)

string = "abc|⚫️\n⚪️|👨‍👩‍👧‍👧"

console.log({ 'string': string }) // abc|⚫️\n⚪️|👨‍👩‍👧‍👧
console.log({ 'string.length': string.length }) // 21

for (let i = 0; i < string.length; i += 1) {
  console.log({ 'string[i]': string[i] }) // byte per byte
  console.log({ 'string.charAt(i)': string.charAt(i) }) // byte per byte
}

for (let char of string) {
  console.log({ 'for char of string': char }) // character groups
}

for (let char in string) {
  console.log({ 'for char in string': char }) // index of byte per byte
}

string.replace(/./g, (char) => {
  console.log({ 'string.replace(/./g, ...)': char }) // byte per byte
});

string.replace(/[\S\s]/g, (char) => {
  console.log({ 'string.replace(/[\S\s]/g, ...)': char }) // byte per byte
});

[...string].forEach((char) => {
  console.log({ "[...string].forEach": char }) // character groups
})

string.split('').forEach((char) => {
  console.log({ "string.split('').forEach": char }) // byte per byte
})

Array.from(string).forEach((char) => {
  console.log({ "Array.from(string).forEach": char }) // character groups
})

Array.prototype.map.call(string, (char) => {
  console.log({ "Array.prototype.map.call(string, ...)": char }) // byte per byte
})

var regexp = /(?:[\0-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])/g

string.replace(regexp, (char) => {
  console.log({ 'str.replace(regexp, ...)': char }) // character groups
});


7

Ora puoi iterare su singoli punti di codice Unicode contenuti in una stringa usando String.prototype[@@iterator], che restituisce un valore di tipo Symbol ben noto Symbol.iterator- l'iteratore predefinito per oggetti simili a array ( Stringin questo caso).

Codice di esempio:

const str = 'The quick red 🦊 jumped over the lazy 🐶! 太棒了!';

let iterator = str[Symbol.iterator]();
let theChar = iterator.next();

while(!theChar.done) {
  console.log(theChar.value);
  theChar = iterator.next();
}

// logs every unicode character as expected into the console.

Funziona con personaggi Unicode come emoji o caratteri non romani che potrebbero inciampare in costruzioni legacy.

Riferimento: MDN Link a String.prototype @@ iterator .


2
Nota che puoi farlo in modo più breve con un for ... ofciclo e anche sopra la stringa, ovvero zucchero di sintassi per accedere all'iteratore.
Aditya MP,

6

È ora possibile utilizzare in parola chiave.

    var s = 'Alien';
    for (var c in s) alert(s[c]);


L'uso in è una cattiva pratica e orribile quando non filtrato, sconsiglio vivamente di
farlo

4
@Downgoat perché? Cosa c'è di male? Voglio dire se mi trovo in una situazione in cui so che "in" è supportato dal mio motore Javascript e che il mio codice non troverà la sua strada in un altro motore ... perché non usarlo?
TKoL,

@TKoL Vedi questo .
Alan

@Alan inè una parte legittima della lingua. Usa le cose in modo appropriato. Il tuo articolo avverte che ininterpreta i tasti alfabetici come i tasti numerici. Così? Forse è quello che vuoi. Si potrebbe anche dire che altri metodi ignorano erroneamente le chiavi alfa. Imo, ofha un comportamento corretto. Negli array JS, gli elementi senza chiavi alfa hanno ancora le chiavi: quelle numeriche. Nella mia console, JS tratta "correttamente" la chiave alfa come i tasti numerici:>const arr = ['a', 'b'] >arr.test = 'hello' >arr 0: "a" 1: "b" test: "hello" length: 2
johny perché

5

È possibile ottenere una serie di singoli personaggi in questo modo

var test = "test string",
    characters = test.split('');

e poi esegui il ciclo usando il normale Javascript, oppure puoi scorrere i caratteri della stringa usando jQuery di

var test = "test string";

$(test.split('')).each(function (index,character) {
    alert(character);
});

5

puoi convertire questa stringa in una matrice di caratteri usando split(), quindi scorrere attraverso di essa.

const str = "javascript";
const strArray = str.split('');

strArray.map(s => console.log(s));


apparentemente questo fallisce con caratteri unicode e simboli grafici.
johny perché

4

Se vuoi fare una trasformazione del testo a livello di carattere e riavere il testo trasformato alla fine, dovresti fare qualcosa del genere:

var value = "alma";
var new_value = value.split("").map(function(x) { return x+"E" }).join("")

Quindi i passaggi:

  • Dividi la stringa in un array (elenco) di caratteri
  • Mappa ogni personaggio tramite un funzione
  • Unisci l'array risultante di caratteri insieme nella stringa risultante

0

Nel JavaScript di oggi puoi

Array.prototype.map.call('This is my string', (c) => c+c)

Ovviamente, c + c rappresenta qualunque cosa tu voglia fare con c.

Questo ritorna

["TT", "hh", "ii", "ss", " ", "ii", "ss", " ", "mm", "yy", " ", "ss", "tt", "rr", "ii", "nn", "gg"]


Forse:[...'This is my string'].map((c)=>c+c)
Alan

0

Questo dovrebbe funzionare nei browser più vecchi e con caratteri UTF-16 come 💩.

Questa dovrebbe essere la soluzione più compatibile. Tuttavia, è meno performante di quanto forsarebbe un loop.

Ho generato l'espressione regolare usando regexpu

var str = 'My String 💩 ';
var regEx = /(?:[\0-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])/g


str.replace(regEx, function (char) {
    console.log(char)
});

Spero che sia di aiuto!


Cosa intendi con "meno perfomante"? Penso che intendi "più lento" in quanto è più conforme al requisito e funziona bene.
hippietrail

-1

Puoi accedere a singoli caratteri con str.charAt(index)o str[index]. Ma quest'ultimo modo non fa parte di ECMAScript, quindi è meglio andare con il primo.


Starei lontano da quello. Purtroppo ciò non funziona in tutte le versioni di IE. Fidati di me. L'ho imparato a mie spese.
Xavi,

3
Fa parte di ECMAScript, ma solo nella quinta edizione appena rilasciata, non in terza.
Kangax,

-1

Se vuoi animare ogni personaggio potresti doverlo avvolgere nell'elemento span;

var $demoText = $("#demo-text");
$demoText.html( $demoText.html().replace(/./g, "<span>$&amp;</span>").replace(/\s/g, " "));

Penso che questo sia il modo migliore per farlo, quindi elaborare gli span. (ad esempio con TweenMax)

TweenMax.staggerFromTo ($ demoText.find ("span"), 0.2, {autoAlpha: 0}, {autoAlpha: 1}, 0.1);


-1

Prova questo codice

    function myFunction() {
    var text =(document.getElementById("htext").value); 
    var meow = " <p> <,> </p>";
    var i;


    for (i = 0; i < 9000; i++) {

        text+=text[i] ;



    }

    document.getElementById("demo2").innerHTML = text;

}
</script>
<p>Enter your text: <input type="text" id="htext"/>

    <button onclick="myFunction();">click on me</button>
</p>
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.