¿Cómo puedo procesar cada letra de texto usando Javascript?

363

Me gustaría alertar a cada letra individual de una cadena, pero no estoy seguro de cómo hacerlo.

Entonces, si tengo:

var str = 'This is my string';

Me gustaría poder alertar por separado T, h, i, s, etc. Esto es solo el comienzo de una idea en la que estoy trabajando, pero necesito saber cómo procesar cada letra por separado.

Quiero usar jQuery y estaba pensando que podría necesitar usar la función de división después de probar cuál es la longitud de la cadena.

Ideas?

Nic Hubbard
fuente
3
Tal vez estabas buscando esto: a partir de ES6, existe for(const c of str) { ... }. Más de eso más abajo en una respuesta bastante detallada pero no suficientemente votada. PD: el enlace de @ ARJUN no funciona para mí.
Max

Respuestas:

421

Si el orden de las alertas es importante, use esto:

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

Si el orden de las alertas no importa, use esto:

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

Eli Gray
fuente
2
usar []IE para obtener el carácter en una posición específica no es compatible con IE <9
vsync
13
como se cubre en la otra respuesta, puede usar str.charAt (i) en lugar de [] 's. para más información sobre por qué debería usar charAt vs [], vea string.charAt (x) o string [x]
Julian Soro
12
Me resulta difícil creer que cualquier compilador JS moderno vuelva a calcular la longitud si la cadena no se ha modificado dentro del bucle. En cualquier otro idioma, con mucho gusto haría la verificación de longitud en la cláusula de prueba del bucle for, suponiendo que el compilador lo sepa mejor y lo optimice en consecuencia.
Echelon
3
@Dagmar: Javascript no usa UTF-8, usa UTF-16 (o UCS-2, dependiendo del navegador). Cada carácter puede representarse como UTF-8 o UTF-16 pero no tiene este problema. Los únicos que tienen el problema son los que requieren cuatro bytes en UTF-16 en lugar de dos bytes. 💩 es un carácter que requiere cuatro bytes en UTF-16. Los términos clave para buscar más información son "plano astral", "no BMP" y "par sustituto".
hippietrail
1
@Dagmar: Java y Javascript tienen UTF-16 (anteriormente UCS-) en común. La tercera plataforma principal que lo utiliza es Windows. Los protocolos de Unix, MacOS e Internet usan UTF-8. charAtQueda de los días de UCS-2 cuando no había pares sustitutos y para abordar el problema, codepointAtse agregó una nueva función a JavaScript que maneja correctamente nuestro amistoso montón de popó. Creo que Java también lo tiene.
hippietrail
240

Probablemente esté más que resuelto. Solo quiero contribuir con otra solución simple:

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);
});
Señor goferito
fuente
44
el último ejemplo puede ser simplemente[...text].forEach(console.log)
Govind Rai
10
No, no puede. forEach()pasa el índice y la matriz como segundo y tercer argumento. Preferiría no registrar eso ...
Sr. Goferito
1
Tenga en cuenta que tanto el operador de propagación (primer ejemplo) como la llamada dividida (último ejemplo) crearán una nueva matriz. Esto generalmente no será un problema, pero podría ser costoso para cadenas grandes o usos frecuentes.
Randolpho
¿Qué hay defor (let c of [...text]) { console.log(c) }
Flimm
Con eso creas una nueva matriz a partir de la cadena. No veo el beneficio. let c of textYa hace el trabajo.
Sr. Goferito
73

Una posible solución en javascript puro:

for (var x = 0; x < str.length; x++)
{
    var c = str.charAt(x);
    alert(c);
}
miku
fuente
Probablemente sería mejor con var x = 0 y var c = str.charAt (x).
Rico
2
Además, str.length debe almacenarse en una variable para que no tenga que seguir accediéndose.
Eli Gray
8
@EliGrey ¿Es realmente tan importante poner longitud en una variable? ¿Tiene puntos de referencia cuando esto sería preferible a tener menos líneas de código?
pm_labs
@paul_sns Curiosamente, parece haber una pequeña diferencia, al menos en Edge (diferencia de 0.7ms para una matriz de 10000 elementos): jsfiddle.net/carcigenicate/v8vvjoc1/1 . Probablemente no sea una prueba perfecta, pero se basa en un promedio de 10000 pruebas.
Carcigenicate
1
@paul_sns También es interesante que Chrome hizo la misma prueba en aproximadamente el 2% del tiempo (~ 5 ms frente a ~ 0.0997 ms), y ambas versiones dieron el mismo tiempo, por lo que parece que Edge no está optimizado.
Carcigenicate
69

Cómo procesar cada letra de texto (con puntos de referencia)

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

para

Clásico y, con mucho, el que tiene el mayor rendimiento . Debería optar por este si planea utilizarlo en un algoritmo de rendimiento crítico, o si requiere la máxima compatibilidad con las versiones del navegador.

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

para ... de

for ... of es el nuevo ES6 para iterador. Compatible con la mayoría de los navegadores modernos. Es visualmente más atractivo y es menos propenso a errores de tipeo. Si va a utilizar este en una aplicación de producción, probablemente debería estar utilizando un transpilador como Babel .

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

para cada

Enfoque funcional . Airbnb aprobado . El mayor inconveniente de hacerlo de esta manera es split()que crea una nueva matriz para almacenar cada letra individual de la cadena.

¿Por qué? Esto hace cumplir nuestra regla inmutable. Tratar con funciones puras que devuelven valores es más fácil de razonar que los efectos secundarios.

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

o

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

Los siguientes son los que no me gustan.

para ... en

A diferencia de ... de, obtienes el índice de la letra en lugar de la letra. Funciona bastante mal.

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

mapa

Enfoque funcional, que es bueno. Sin embargo, el mapa no está destinado a ser utilizado para eso. Debe usarse cuando necesite cambiar los valores dentro de una matriz, que no es el caso.

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

o

let result = '';
str.split('').map(function(letter) {
  result += letter;
});
zurfyx
fuente
1
En mi máquina, el forbucle clásico fue en realidad el segundo más lento, mientras que for...offue el más rápido (aproximadamente tres veces más rápido que for).
John Montgomery
1
¿Dónde está el punto de referencia? ¿Cuál es la solución más rápida?
poitroae
1
@johnywhy Eso fue hace dos años y el enlace está muerto, así que no estoy seguro de cómo esperas que defienda el resultado que obtuve en ese momento. Sin embargo, configurar un nuevo punto de referencia ahora está de acuerdo con la conclusión de zurfyx, con el forciclo siendo un poco más rápido.
John Montgomery
1
@JohnMontgomery No espero que hagas nada. Solo una nota para los futuros lectores que sus resultados son diferentes a la respuesta. Personalmente, me gustaría saber qué resultados se aplican a los navegadores hoy 2020, aunque '2018 no fue hace tanto tiempo. ¿Qué enlace está muerto?
Johnny, ¿por qué
1
@johnywhy El enlace en la parte superior con todas las pruebas reales me devuelve un 404.
John Montgomery
42

La mayoría de las respuestas, si no todas, son incorrectas porque se romperán cuando haya un carácter en la cadena fuera del Unicode BMP (Plano multilingüe básico) . Eso significa que todos los Emoji estarán rotos .

JavaScript utiliza UTF- 16 Unicode para todas las cadenas. En UTF-16, los caracteres más allá del BMP están formados por dos partes, llamadas " Par sustituto " y la mayoría de las respuestas aquí procesarán cada parte de dichos pares individualmente en lugar de un solo carácter.

Una forma en JavaScript moderno desde al menos 2016 es usar el nuevo iterador de cadena . Aquí está el ejemplo (casi) directamente de 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"

hippietrail
fuente
44
Para obtener una solución moderna para dividir una cadena en caracteres teniendo en cuenta los pares sustitutos, consulte: stackoverflow.com/a/42596897/527702
hippietrail
20

Puedes probar esto

var arrValues = 'This is my string'.split('');
// Loop over each value in the array.
$.each(arrValues, function (intIndex, objValue) {
    alert(objValue);
})
Adriaan Stander
fuente
11
Aún así es una opción, pero no de alto rendimiento. No pongas jQuery en todas partes.
cagatay
10

Una solución más ...

var strg= 'This is my string';
for(indx in strg){
  alert(strg[indx]);
}
Pamsix
fuente
3
Si solo quieres el carácter y no el índice, sería más rápido usar un for..ofbuclefor (let ch of t) { alert(ch) }
Shaheen Ghiassy
10

Cuando necesito escribir un código corto o una línea, utilizo este "hack":

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

Esto no contará nuevas líneas, por lo que puede ser algo bueno o malo. Si desea incluir nuevas líneas, reemplace: /./con /[\S\s]/. Las otras frases que puede ver probablemente usen, lo .split()que tiene muchos problemas

Downgoat
fuente
la mejor respuesta. Tiene en cuenta los problemas con Unicode y también se puede usar con construcciones funcionales con .map () etc.
rofrol
Lo único que no me gusta de este es cuando quiero acceder a los parámetros adicionales pasados ​​a la forEachfunción de la llamada frente a los parámetros enviadosreplace . Si sé que estoy ASCIIANDO, creo que todavía tengo algunos casos de uso para split. ¡Gran respuesta, sin embargo!
ruffin
Esta respuesta tiene la ventaja de preseleccionar los valores con los que verificaría de todos modos
Fuzzyma
1
Pensé que esto no tendría en cuenta los problemas de Unicode a menos que tuviera la ubandera junto con la gbandera. OK solo probé y tenía razón.
hippietrail
9

El nuevo JS permite esto:

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

Es mejor usar la instrucción for ... of, si la cadena contiene caracteres unicode, debido al diferente tamaño de byte.

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

respuesta corta: Array.from(string)te dará lo que probablemente quieras y luego podrás repetirlo o lo que sea, ya que es solo una matriz.

ok vamos a intentarlo con esta cadena: abc|⚫️\n⚪️|👨‍👩‍👧‍👧.

los puntos de código son:

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

entonces algunos caracteres tienen un punto de código (byte) y algunos tienen dos o más, y se agrega una nueva línea para pruebas adicionales.

así que después de probar hay dos formas:

  • byte por byte (punto de código por punto de código)
  • grupos de personajes (pero no los emoji de toda la familia)

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

localhostdotdev
fuente
7

Ahora puede iterar sobre puntos de código Unicode individuales contenidos en una Cadena mediante el uso String.prototype[@@iterator], que devuelve un valor de tipo de símbolo bien conocido Symbol.iterator: el iterador predeterminado para objetos tipo matriz ( Stringen este caso).

Código de ejemplo:

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.

Esto funciona con caracteres Unicode, como emoji o caracteres no romanos que tropezarían con construcciones heredadas.

Referencia: MDN Link to String.prototype @@ iterator .

Aditya MP
fuente
2
Tenga en cuenta que puede hacer esto de una manera más corta con un for ... ofbucle también sobre la cadena, que es el azúcar de sintaxis para acceder al iterador.
Aditya MP
6

Ahora puede usar en palabras clave.

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

mih0vil
fuente
Usarlo es una mala práctica y horrible cuando no está filtrado. Recomiendo encarecidamente esto
Downgoat
44
@Downgoat ¿por qué? ¿Qué tiene de malo? Quiero decir, si estoy en una situación en la que sé que 'in' es compatible con mi motor Javascript, y que mi código no llegará a otro motor ... ¿por qué no usar eso?
TKoL
@TKoL Mira esto .
Alan
@Alan ines una parte legítima del lenguaje. Usa las cosas apropiadamente. Su artículo advierte que ininterpreta las teclas alfa igual que las teclas numéricas. ¿Entonces? Tal vez eso es lo que quieres. También se podría decir que otros métodos ignoran incorrectamente las claves alfa. Imo, oftiene el comportamiento correcto. En las matrices JS, los elementos sin claves alfa aún tienen claves: numéricas. En mi consola, JS trata "correctamente" la clave alfa igual que las teclas numéricas:>const arr = ['a', 'b'] >arr.test = 'hello' >arr 0: "a" 1: "b" test: "hello" length: 2
johny por qué
5

Puede obtener una variedad de los caracteres individuales de esta manera

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

y luego bucle usando Javascript regular, o puede iterar sobre los caracteres de la cadena usando jQuery por

var test = "test string";

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

puede convertir esta cadena en una matriz de caracteres utilizando split(), luego iterar a través de ella.

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

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

Muhammed Moussa
fuente
aparentemente esto falla con caracteres unicode y símbolos gráficos.
Johnny, ¿por qué
4

Si desea realizar una transformación en el texto a nivel de caracteres y recuperar el texto transformado al final, debería hacer algo como esto:

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

Entonces los pasos:

  • Divida la cadena en una matriz (lista) de caracteres
  • Mapa de cada personaje a través de un functor
  • Unir el conjunto resultante de caracteres en la cadena resultante
Vajk Hermecz
fuente
0

En el JavaScript de hoy puedes

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

Obviamente, c + c representa lo que quieras hacer con c.

Esto vuelve

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

Pum Walters
fuente
Posiblemente:[...'This is my string'].map((c)=>c+c)
Alan
0

Esto debería funcionar en navegadores antiguos y con caracteres UTF-16 como 💩.

Esta debería ser la solución más compatible. Sin embargo, es menos eficaz de lo que forsería un bucle.

Genere la expresión regular 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)
});

¡Espero que esto ayude!

Ben Gubler
fuente
¿Qué quieres decir con "menos perfumante"? Creo que te refieres a "más lento", ya que es más conforme al requisito y funciona bien.
hippietrail
-1

Puede acceder a caracteres individuales con str.charAt(index)o str[index]. Pero la última forma no es parte de ECMAScript, por lo que es mejor que elija la primera.

Gumbo
fuente
Me mantendría alejado de eso. Lamentablemente, eso no funciona en todas las versiones de IE. Créeme. Lo aprendí de la manera difícil.
Xavi
3
Es parte de ECMAScript, pero solo en la quinta edición recién lanzada, no en la tercera.
kangax
-1

Si desea animar cada personaje, es posible que necesite envolverlo en el elemento span;

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

Creo que esta es la mejor manera de hacerlo, luego procesar los tramos. (por ejemplo con TweenMax)

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

Chris Panayotoff
fuente
-1

Prueba este código

    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>
maullar
fuente