Como você obtém uma string para uma matriz de caracteres em JavaScript?

369

Como você converte uma string em uma matriz de caracteres em JavaScript?

Eu estou pensando em obter uma string como "Hello world!"a matriz
['H','e','l','l','o',' ','w','o','r','l','d','!']

DarkLightA
fonte

Respostas:

492

Nota: Isso não é compatível com unicode. "I💖U".split('')resulta na matriz de 4 caracteres ["I", "�", "�", "u"]que pode levar a erros perigosos. Veja as respostas abaixo para alternativas seguras.

Apenas divida-o por uma string vazia.

var output = "Hello world!".split('');
console.log(output);

Veja os String.prototype.split()documentos MDN .

meder omuraliev
fonte
31
Isso não leva em consideração pares substitutos. "𨭎".split('')resulta em ["�", "�"].
Hippietrail
59
Veja a resposta de @ hakatashi em outras partes deste tópico. Espero que todo mundo vê isso ... Não use este método, não é UNICODE SAFE
i336_
3
Um pouco atrasado para a festa. Mas por que alguém iria querer criar uma matriz de uma string? Uma string já é uma matriz ou estou errado? "randomstring".length; //12 "randomstring"[2]; //"n"
Luigi van der Pal
4
@LuigivanderPal Uma string não é uma matriz, mas é muito semelhante. No entanto, não é semelhante a uma matriz de caracteres. Uma string é semelhante a uma matriz de números de 16 bits, alguns dos quais representam caracteres e outros representam metade de um par substituto. Por exemplo, str.lengthnão informa o número de caracteres na sequência, pois alguns caracteres ocupam mais espaço que outros; str.lengthinforma o número de números de 16 bits.
Theodore Norvell
290

Como sugere o hippietrail , a resposta do médico pode quebrar pares substitutos e interpretar mal os "caracteres". Por exemplo:

// DO NOT USE THIS!
> '𝟘𝟙𝟚𝟛'.split('')
[ '�', '�', '�', '�', '�', '�', '�', '�' ]

Sugiro usar um dos seguintes recursos do ES2015 para lidar corretamente com essas seqüências de caracteres.

Sintaxe de propagação ( já respondida por insertusernamehere)

> [...'𝟘𝟙𝟚𝟛']
[ '𝟘', '𝟙', '𝟚', '𝟛' ]

Array.from

> Array.from('𝟘𝟙𝟚𝟛')
[ '𝟘', '𝟙', '𝟚', '𝟛' ]

RegExp ubandeira

> '𝟘𝟙𝟚𝟛'.split(/(?=[\s\S])/u)
[ '𝟘', '𝟙', '𝟚', '𝟛' ]

Use em /(?=[\s\S])/uvez de /(?=.)/uporque .não corresponde a novas linhas .

Se você ainda está na era ES5.1 (ou se o navegador não manipula esse regex corretamente - como o Edge), você pode usar esta alternativa (transpilada por Babel ):

> '𝟘𝟙𝟚𝟛'.split(/(?=(?:[\0-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]))/);
[ '𝟘', '𝟙', '𝟚', '𝟛' ]

Observe que Babel também tenta manipular substitutos não correspondentes corretamente. No entanto, isso não parece funcionar para substitutos baixos incomparáveis.

Teste tudo no seu navegador:

hakatashi
fonte
Como você formou esses personagens? Parece que cada caractere tem 4 bytes.
User420667
2
@ user420667 os caracteres são de um plano de caracteres adicional (na tabela unicode) com pontos de código "grandes", portanto, não cabem em 16 bytes. A codificação utf-16 usada no javascript apresenta esses caracteres como pares substitutos (caracteres especiais que são usados ​​apenas como pares para formar outros caracteres de planos adicionais). Somente os caracteres do plano principal de caracteres são apresentados com 16 bytes. Os caracteres especiais do par substituto também são do plano do personagem principal, se isso faz sentido.
Olga
11
Desempenho das diferentes técnicas , o spread op se parece com o campeão (chrome 58).
Adrien
4
Observe que esta solução divide alguns emoji como 🏳️‍🌈, e divide a combinação de sinais diacríticos de caracteres. Se você deseja dividir em clusters de grafema em vez de caracteres, consulte stackoverflow.com/a/45238376 .
usar o seguinte comando
3
Observe que, embora não seja ótimo separar pares substitutos, não é uma solução de uso geral para manter "caracteres" (ou, mais precisamente, grafemas ) juntos. Um grafema pode ser composto de vários pontos de código; por exemplo, o nome da linguagem de Devanagari é "देवनागरी", que é lido por um falante nativo como cinco grafemas, mas leva oito pontos de código para produzir ...
TJ Crowder
71

A spreadsintaxe

Você pode usar a sintaxe de propagação , um Array Initializer introduzido no padrão ECMAScript 2015 (ES6) :

var arr = [...str];

Exemplos

function a() {
    return arguments;
}

var str = 'Hello World';

var arr1 = [...str],
    arr2 = [...'Hello World'],
    arr3 = new Array(...str),
    arr4 = a(...str);

console.log(arr1, arr2, arr3, arr4);

Os três primeiros resultam em:

["H", "e", "l", "l", "o", " ", "W", "o", "r", "l", "d"]

O último resulta em

{0: "H", 1: "e", 2: "l", 3: "l", 4: "o", 5: " ", 6: "W", 7: "o", 8: "r", 9: "l", 10: "d"}

Suporte do navegador

Verifique a tabela de compatibilidade do ECMAScript ES6 .


Leitura adicional

spreadtambém é referenciado como " splat" (por exemplo, em PHP ou Ruby ou como " scatter" (por exemplo, em Python ).


Demo

Experimente antes de comprar

insertusernamehere
fonte
11
Se você usar o operador spread em combinação com um compilador para o ES5, isso não funcionará no IE. Leve isso em consideração. Levei horas para descobrir qual era o problema.
precisa
14

Você também pode usar Array.from.

var m = "Hello world!";
console.log(Array.from(m))

Este método foi introduzido no ES6.

Referência

Array.from

Rajesh
fonte
10

Esta é uma pergunta antiga, mas me deparei com outra solução ainda não listada.

Você pode usar a função Object.assign para obter a saída desejada:

var output = Object.assign([], "Hello, world!");
console.log(output);
    // [ 'H', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '!' ]

Não necessariamente certo ou errado, apenas outra opção.

Object.assign está bem descrito no site MDN.

David Thomas
fonte
2
É um longo caminho a percorrer Array.from("Hello, world").
TJ Crowder
@TJCrowder Isso é um caminho mais longo para chegar a[..."Hello, world"]
chharvey
@chharvey - Heh. :-)
TJ Crowder
9

Já é:

var mystring = 'foobar';
console.log(mystring[0]); // Outputs 'f'
console.log(mystring[3]); // Outputs 'b'

Ou, para uma versão mais antiga do navegador, use:

var mystring = 'foobar';
console.log(mystring.charAt(3)); // Outputs 'b'

dansimau
fonte
4
-1: não é. Tente:alert("Hello world!" == ['H','e','l','l','o',' ','w','o','r','l','d'])
R. Martinho Fernandes
5
Desculpa. Eu acho que o que eu quis dizer é: "você pode acessar caracteres individuais por referência de índice como esta sem criar uma matriz de caracteres".
dansimau
3
Não é confiável em vários navegadores, você não pode. É um recurso da quinta edição do ECMAScript.
bobince
8
A versão entre navegadores é mystring.charAt(index).
psmay
11
+1 para - charAt()embora eu prefira usar a variante array-ish. Maldito IE.
Zenexer 04/07/2014
4

Existem (pelo menos) três coisas diferentes que você pode conceber como um "personagem" e, consequentemente, três categorias diferentes de abordagem que você pode querer usar.

Divisão em unidades de código UTF-16

As strings JavaScript foram originalmente inventadas como sequências de unidades de código UTF-16, em um ponto no histórico em que havia um relacionamento individual entre as unidades de código UTF-16 e os pontos de código Unicode. A .lengthpropriedade de uma corda mede seu comprimento em UTF-16 unidades de código, e quando você faz someString[i]você obter o i th unidade de código UTF-16 de someString.

Conseqüentemente, você pode obter uma matriz de unidades de código UTF-16 de uma string usando um loop for do estilo C com uma variável de índice ...

const yourString = 'Hello, World!';
const charArray = [];
for (let i=0; i<=yourString.length; i++) {
    charArray.push(yourString[i]);
}
console.log(charArray);

Também existem várias maneiras curtas de conseguir a mesma coisa, como usar .split()a string vazia como separador:

const charArray = 'Hello, World!'.split('');
console.log(charArray);

No entanto, se sua sequência contiver pontos de código compostos por várias unidades de código UTF-16, isso as dividirá em unidades de código individuais, que podem não ser o que você deseja. Por exemplo, a cadeia '𝟘𝟙𝟚𝟛'é composta de quatro pontos de código unicode (pontos de código 0x1D7D8 a 0x1D7DB) que, em UTF-16, são compostos por duas unidades de código UTF-16. Se dividirmos essa sequência usando os métodos acima, obteremos uma matriz de oito unidades de código:

const yourString = '𝟘𝟙𝟚𝟛';
console.log('First code unit:', yourString[0]);
const charArray = yourString.split('');
console.log('charArray:', charArray);

Divisão em pontos de código Unicode

Portanto, talvez desejemos dividir nossa string em pontos de código Unicode! Isso é possível desde que o ECMAScript 2015 adicionou o conceito de iterável ao idioma. As strings agora são iteráveis ​​e, quando você as itera (por exemplo, com um for...ofloop), obtém pontos de código Unicode, não unidades de código UTF-16:

const yourString = '𝟘𝟙𝟚𝟛';
const charArray = [];
for (const char of yourString) {
  charArray.push(char);
}
console.log(charArray);

Podemos encurtar isso usando Array.from , que itera sobre o iterável que é passado implicitamente:

const yourString = '𝟘𝟙𝟚𝟛';
const charArray = Array.from(yourString);
console.log(charArray);

No entanto, pontos de código Unicode não são a maior coisa que poderia possivelmente ser considerado um "caráter" quer . Alguns exemplos de coisas que poderiam razoavelmente ser consideradas um único "caractere", mas constituídos por vários pontos de código incluem:

  • Caracteres acentuados, se o acento for aplicado com um ponto de código combinado
  • Bandeiras
  • Alguns emojis

Podemos ver abaixo que, se tentarmos converter uma string com esses caracteres em uma matriz por meio do mecanismo de iteração acima, os caracteres acabam sendo divididos na matriz resultante. (Caso algum dos personagens não seja renderizado em seu sistema, yourStringabaixo é composto por uma letra maiúscula A com sotaque agudo, seguida pela bandeira do Reino Unido e por uma mulher negra.)

const yourString = 'Á🇬🇧👩🏿';
const charArray = Array.from(yourString);
console.log(charArray);

Se queremos manter cada um deles como um único item em nossa matriz final, precisamos de uma matriz de grafemas , não de pontos de código.

Dividindo em grafemas

O JavaScript não tem suporte interno para isso - pelo menos ainda não. Portanto, precisamos de uma biblioteca que entenda e implemente as regras Unicode para qual combinação de pontos de código constitui um grafema. Felizmente, existe um: o divisor de grafemas de orling . Você deseja instalá-lo com o npm ou, se não estiver usando o npm, faça o download do arquivo index.js e sirva-o com uma <script>tag. Para esta demonstração, carrego-a no jsDelivr.

grafema-divisor nos dá uma GraphemeSplitterclasse com três métodos: splitGraphemes, iterateGraphemes, e countGraphemes. Naturalmente, queremos splitGraphemes:

const splitter = new GraphemeSplitter();
const yourString = 'Á🇬🇧👩🏿';
const charArray = splitter.splitGraphemes(yourString);
console.log(charArray);
<script src="https://cdn.jsdelivr.net/npm/[email protected]/index.js"></script>

E aqui estamos - uma série de três grafemas, que provavelmente é o que você queria.

Mark Amery
fonte
2

Você pode percorrer o comprimento da string e pressionar o caractere em cada posição :

const str = 'Hello World';

const stringToArray = (text) => {
  var chars = [];
  for (var i = 0; i < text.length; i++) {
    chars.push(text[i]);
  }
  return chars
}

console.log(stringToArray(str))

Mohit Rathore
fonte
11
Embora essa abordagem seja um pouco mais imperativa do que declarativa, ela é a mais bem-sucedida de todas neste segmento e merece mais amor. Uma limitação para recuperar um caractere em uma sequência de caracteres por posição é quando se lida com caracteres anteriores ao Plano Multilíngue Básico em unicode, como emojis. "😃".charAt(0)retornará um carácter inutilizável
KyleMit
2
@KyleMit isso parece verdade apenas para uma entrada curta. Usando uma entrada mais torna .split("")a opção mais rápida novamente
Lux
11
Também .split("")parece ser fortemente otimizado no firefox. Enquanto o loop tem desempenho semelhante no chrome e no firefox, a divisão é significativamente mais rápida no firefox para entradas pequenas e grandes.
Lux
2

resposta simples:

let str = 'this is string, length is >26';

console.log([...str]);

ajit kumar
fonte
-1; isso não acrescenta nada que já não estivesse incluído na resposta do hakatashi .
Mark Amery
0

Uma possibilidade é a seguinte:

console.log([1, 2, 3].map(e => Math.random().toString(36).slice(2)).join('').split('').map(e => Math.random() > 0.5 ? e.toUpperCase() : e).join(''));
user2301515
fonte
-1

Que tal agora?

function stringToArray(string) {
  let length = string.length;
  let array = new Array(length);
  while (length--) {
    array[length] = string[length];
  }
  return array;
}
msand
fonte
@KyleMit este parece mais rápido do loop for i + empurrar jsperf.com/string-to-character-array/3
msand
-1

Array.prototype.slice também fará o trabalho.

const result = Array.prototype.slice.call("Hello world!");
console.log(result);

f3tknco
fonte