Como posso processar cada letra de texto usando Javascript?

363

Gostaria de alertar cada letra individual de uma string, mas não tenho certeza de como fazer isso.

Então, se eu tiver:

var str = 'This is my string';

Eu gostaria de poder alertar separadamente T, h, i, s, etc. Este é apenas o começo de uma idéia em que estou trabalhando, mas preciso saber como processar cada letra separadamente.

Eu quero usar jQuery e estava pensando que talvez eu precise usar a função de divisão depois de testar qual é o comprimento da string.

Ideias?

Nic Hubbard
fonte
3
Talvez você estivesse procurando por isso: a partir do ES6, existe for(const c of str) { ... }. Mais adiante, em uma resposta bastante detalhada, mas não suficientemente votada. PS: O link do @ ARJUN não funciona para mim.
Max

Respostas:

421

Se a ordem dos alertas for importante, use o seguinte:

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

Se a ordem dos alertas não importar, use o seguinte:

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

Eli Gray
fonte
2
usando o []para obter o caractere em uma posição específica não é suportado no IE <9
vsync
13
conforme abordado na outra resposta, você pode usar str.charAt (i) no lugar dos [] 's. Para saber mais sobre por que você deve usar charAt vs [], consulte String.charAt (x) ou string [x]
Julian Soro
12
Acho difícil acreditar que qualquer compilador JS moderno recalcule o comprimento se a string não tiver sido modificada dentro do loop. Em qualquer outro idioma, eu faria felizmente a verificação do comprimento na cláusula de teste do loop for, assumindo que o compilador saiba melhor e que o otimize adequadamente.
Echelon
3
@Dagmar: Javascript não usa UTF-8, ele usa UTF-16 (ou UCS-2, dependendo do navegador). Cada caractere único pode ser representado como UTF-8 ou UTF-16, mas não possui esse problema. Os únicos que têm o problema são os que requerem quatro bytes em UTF-16 em vez de dois bytes. 💩 é um caractere que requer quatro bytes em UTF-16. Os principais termos para procurar mais informações são "plano astral", "não BMP" e "par substituto".
Hippietrail
11
@Dagmar: Java e Javascript têm UTF-16 (anteriormente UCS-) em comum. A terceira plataforma principal que o utiliza é o Windows. Os protocolos Unix, MacOS e Internet usam UTF-8. charAté deixado nos dias UCS-2, quando não havia pares substitutos e, para resolver o problema, uma nova função codepointAtfoi adicionada ao JavaScript que lida com nossa pilha amigável de cocô corretamente. Eu acredito que Java também tem.
Hippietrail 28/02
240

Provavelmente está mais do que resolvido. Só quero contribuir com outra solução simples:

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);
});
Mr. Goferito
fonte
4
o último exemplo pode ser simplesmente[...text].forEach(console.log)
Govind Rai
10
Não, não pode. forEach()passa o índice e a matriz como segundo e terceiro argumento. Eu preferiria não registrar isso ..
Sr. Goferito 01/08/19
11
Observe que o operador de spread (primeiro exemplo) e a chamada dividida (último exemplo) criarão uma nova matriz. Isso geralmente não será um problema, mas pode custar caro para cordas grandes ou usos frequentes.
Randolpho
Que talfor (let c of [...text]) { console.log(c) }
Flimm
Com isso, você cria uma nova matriz a partir da string. Eu não vejo o benefício. let c of textjá faz o trabalho.
Goferito 05/11/19
73

Uma solução possível em javascript puro:

for (var x = 0; x < str.length; x++)
{
    var c = str.charAt(x);
    alert(c);
}
miku
fonte
Provavelmente seria melhor com var x = 0 e var c = str.charAt (x).
Rico
2
Além disso, str.length deve ser armazenado em uma variável para que não precise ser acessado.
Eli Gray # /
8
@EliGrey É realmente importante colocar comprimento em uma variável? Você tem referências quando isso seria preferível a ter menos linhas de código?
pm_labs
@paul_sns Curiosamente, parece haver uma pequena diferença, pelo menos no Edge (diferença de 0,7ms para uma matriz de 10000 elementos): jsfiddle.net/carcigenicate/v8vvjoc1/1 . Provavelmente não é um teste perfeito, mas é baseado em uma média de 10.000 testes.
Carcigenicate
11
@paul_sns Também, curiosamente, o Chrome fez o mesmo teste em cerca de 2% das vezes (~ 5ms vs ~ 0.0997ms), e ambas as versões deram o mesmo tempo, então parece que o Edge não está otimizado.
Carcigenicate 6/16
69

Como processar cada letra do texto (com referências)

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

para

Clássico e de longe aquele com mais desempenho . Você deve optar por este caso esteja planejando usá-lo em um algoritmo de desempenho crítico ou se exija a máxima compatibilidade com as versões do navegador.

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

para de

for ... of é o novo ES6 para iterador. Suportado pela maioria dos navegadores modernos. É visualmente mais atraente e menos propenso a erros de digitação. Se você optar por este em um aplicativo de produção, provavelmente deverá usar um transpiler como o Babel .

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

para cada

Abordagem funcional . Airbnb aprovado . A maior desvantagem de fazer dessa maneira é a split(), que cria uma nova matriz para armazenar cada letra individual da string.

Por quê? Isso reforça nossa regra imutável. Lidar com funções puras que retornam valores é mais fácil de raciocinar do que efeitos colaterais.

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

ou

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

A seguir, os que não gosto.

para ... em

Ao contrário de ... of, você obtém o índice de letras em vez da letra. Ele executa muito mal.

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

mapa

Abordagem de função, o que é bom. No entanto, o mapa não deve ser usado para isso. Deve ser usado quando for necessário alterar os valores dentro de uma matriz, o que não é o caso.

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

ou

let result = '';
str.split('').map(function(letter) {
  result += letter;
});
zurfyx
fonte
11
Na minha máquina, o forloop clássico foi o segundo mais lento, enquanto for...ofo mais rápido (cerca de três vezes mais rápido for).
John Montgomery
11
Onde está o benchmark? Qual é a solução mais rápida?
poitroae
11
@johnywhy Isso foi há dois anos e o link está morto, então não tenho certeza de como você espera que eu defenda o resultado que recebi naquela época. A criação de um novo benchmark agora concorda com a conclusão do zurfyx, com o forloop sendo um pouco mais rápido.
John Montgomery
11
@JohnMontgomery Não espero que você faça nada. Apenas uma observação para os futuros leitores de que seus resultados são diferentes da resposta. Pessoalmente, gostaria de saber quais resultados se aplicam aos navegadores hoje em 2020, embora 2018 não fosse há muito tempo. Qual link está morto?
johny why
11
@johnywhy O link na parte superior com todos os testes reais está retornando um 404 para mim.
John Montgomery
42

A maioria, se não todas, as respostas aqui estão erradas, pois elas serão interrompidas sempre que houver um caractere na cadeia de caracteres fora do BMP Unicode (Plano Multilíngue Básico) . Isso significa que todos os Emoji serão quebrados .

JavaScript usa UTF- 16 Unicode para todas as strings. No UTF-16, os caracteres além do BMP são compostos de duas partes, denominadas " Par Substituto " " e a maioria das respostas aqui processará cada parte desses pares individualmente, em vez de um único caractere.

Uma maneira no JavaScript moderno desde pelo menos 2016 é usar o novo iterador String . Aqui está o exemplo (quase) direto do 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
fonte
4
Para uma solução moderna para dividir uma string em caracteres, tendo em conta pares substitutos, consulte: stackoverflow.com/a/42596897/527702
hippietrail
20

Você pode tentar isso

var arrValues = 'This is my string'.split('');
// Loop over each value in the array.
$.each(arrValues, function (intIndex, objValue) {
    alert(objValue);
})
Adriaan Stander
fonte
11
Ainda é uma opção, mas não tem desempenho. Não coloque o jQuery em todos os lugares.
Cagatay 31/01/19
10

Mais uma solução ...

var strg= 'This is my string';
for(indx in strg){
  alert(strg[indx]);
}
Pamsix
fonte
3
Se você quiser apenas o caractere e não o índice, que seria mais rápido para usar um for..ofciclofor (let ch of t) { alert(ch) }
Shaheen Ghiassy
10

Quando eu preciso escrever um código curto ou uma linha, eu uso este "hack":

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

Isso não contará novas linhas para que possa ser uma coisa boa ou ruim. Se você deseja incluir novas linhas, substitua: /./por /[\S\s]/. Os outros one-liners que você pode ver, provavelmente, usar .split()o que tem muitos problemas

Downgoat
fonte
melhor resposta. Leva em conta problemas com unicode e também pode ser usado com construções funcionais com .map () etc.
rofrol
A única coisa que eu não gosto nesse caso é quando quero acessar os parâmetros extras passados ​​para a forEachfunção da chamada versus os parâmetros enviadosreplace . Se eu sei que sou ASCII, acho que ainda tenho alguns casos de uso split. Ótima resposta, no entanto!
Ruffin
Esta resposta tem o bônus com pré-selecção os valores que você iria verificar contra qualquer maneira
Fuzzyma
11
Eu pensei que isso não levaria em conta os problemas de Unicode, a menos que tivesse a ubandeira junto com a gbandeira? OK, apenas testei e eu estava certo.
Hippietrail
9

O novo JS permite isso:

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

É melhor usar a instrução for ..., se a string contiver caracteres unicode, devido ao tamanho de byte diferente.

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

resposta curta: Array.from(string)fornecerá o que você provavelmente deseja e, em seguida, você pode iterá-lo ou o que quer que seja, já que é apenas uma matriz.

ok, vamos tentar com esta string: abc|⚫️\n⚪️|👨‍👩‍👧‍👧 .

Os pontos de código são:

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

portanto, alguns caracteres têm um ponto de código (byte) e outros dois ou mais, e uma nova linha adicionada para testes extras.

então, após o teste, há duas maneiras:

  • byte por byte (ponto de código por ponto de código)
  • grupos de caracteres (mas não o emoji de toda a família)

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
fonte
7

Agora você pode iterar sobre pontos de código Unicode individuais contidos em uma String usando String.prototype[@@iterator], que retorna um valor do tipo Symbol conhecido Symbol.iterator- o iterador padrão para Objetos semelhantes a matrizes (String neste caso).

Código de exemplo:

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.

Isso funciona com caracteres Unicode, como emoji ou caracteres não romanos, que desarmariam construções herdadas.

Referência: Link MDN para String.prototype @@ iterator .

Aditya MP
fonte
2
Observe que você pode fazer isso de maneira mais curta com um for ... ofloop e também sobre a string - que é o açúcar da sintaxe para acessar o iterador.
Aditya MP
6

Agora você pode usar em palavras-chave.

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

mih0vil
fonte
Usando em é uma prática ruim e horrível quando não filtrada Eu recomendo fortemente contra isso
Downgoat
4
@Downgoat why? O que há de ruim nisso? Quero dizer, se estou em uma situação em que sei que o 'in' é suportado pelo meu mecanismo Javascript e que meu código não encontra caminho para outro mecanismo ... por que não usá-lo?
TKoL
@TKoL Veja isso .
Alan
@ Alan iné uma parte legítima da linguagem. Use as coisas adequadamente. Seu artigo adverte que ininterpreta as teclas alfa da mesma forma que as teclas numéricas. Assim? Talvez seja isso que você quer. Também se pode dizer que outros métodos ignoram incorretamente as teclas alfa. Imo, oftem comportamento correto. Nas matrizes JS, os elementos sem as teclas alfa ainda possuem as chaves: os numéricos. No meu console, JS "corretamente" trata a tecla alfa da mesma forma que as teclas numéricas:>const arr = ['a', 'b'] >arr.test = 'hello' >arr 0: "a" 1: "b" test: "hello" length: 2
johny why
5

Você pode obter uma matriz de caracteres individuais como esse

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

e, em seguida, faça um loop usando Javascript comum, ou você pode iterar os caracteres da string usando jQuery por

var test = "test string";

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

você pode converter essa sequência em uma matriz de caracteres usando e split(), em seguida, iterar através dela.

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

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

Muhammed Moussa
fonte
aparentemente isso falha com caracteres unicode e símbolos gráficos.
johny porque
4

Se você deseja fazer uma transformação no texto em um nível de personagem e recuperar o texto transformado no final, faça algo assim:

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

Então, as etapas:

  • Divida a sequência em uma matriz (lista) de caracteres
  • Mapear cada caractere por meio de um functor
  • Associe a matriz de caracteres resultante à string resultante
Vajk Hermecz
fonte
0

No JavaScript de hoje, você pode

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

Obviamente, c + c representa o que você quer fazer com c.

Isso retorna

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

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

Isso deve funcionar em navegadores antigos e com caracteres UTF-16 como 💩.

Essa deve ser a solução mais compatível. No entanto, é menos eficiente que umfor loop seria.

Eu gerei a expressão 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 isto ajude!

Ben Gubler
fonte
O que você quer dizer com "menos perfomant"? Eu acho que você quer dizer "mais lento", pois é mais compatível com o requisito e tem um bom desempenho.
hippietrail
-1

Você pode acessar caracteres únicos com str.charAt(index)ou str[index]. Mas a última maneira não faz parte do ECMAScript, portanto é melhor você optar pela primeira.

quiabo
fonte
Eu ficaria longe disso. Infelizmente, isso não funciona em todas as versões do IE. Confie em mim. Eu aprendi da maneira mais difícil.
Xavi
3
Faz parte do ECMAScript, mas apenas na 5ª edição recém-lançada, não na 3ª.
Kangax
-1

Se você deseja animar cada caractere, pode ser necessário envolvê-lo no elemento span;

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

Eu acho que essa é a melhor maneira de fazer isso, depois processe os intervalos. (por exemplo, com TweenMax)

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

Chris Panayotoff
fonte
-1

Experimente 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>
Miau
fonte