¿Cómo se obtiene una cadena a una matriz de caracteres en JavaScript?

370

¿Cómo se convierte una cadena en una matriz de caracteres en JavaScript?

Estoy pensando en obtener una cadena como "Hello world!"en la matriz
['H','e','l','l','o',' ','w','o','r','l','d','!']

DarkLightA
fuente

Respuestas:

493

Nota: Esto no es compatible con Unicode. "I💖U".split('')da como resultado la matriz de 4 caracteres ["I", "�", "�", "u"]que puede conducir a errores peligrosos. Vea las respuestas a continuación para alternativas seguras.

Simplemente divídalo por una cadena vacía.

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

Ver los String.prototype.split()documentos de MDN .

meder omuraliev
fuente
31
Esto no tiene en cuenta los pares sustitutos. "𨭎".split('')resultados en ["�", "�"].
hippietrail
59
Ver la respuesta de @ hakatashi en otra parte de este hilo. Esperemos que todos vean esto ... NO UTILICE ESTE MÉTODO, NO ES SEGURO DE UNICODE
i336_
3
Un poco tarde para la fiesta. Pero, ¿por qué alguien querría hacer una matriz de una cadena? Una cadena ya es una matriz o estoy equivocado? "randomstring".length; //12 "randomstring"[2]; //"n"
Luigi van der Pal
44
@LuigivanderPal Una cadena no es una matriz, pero es muy similar. Sin embargo, no es similar a una serie de caracteres. Una cadena es similar a una matriz de números de 16 bits, algunos de los cuales representan caracteres y otros la mitad de un par sustituto. Por ejemplo, str.lengthno le indica el número de caracteres en la cadena, ya que algunos caracteres ocupan más espacio que otros; str.lengthle dice el número de números de 16 bits.
Theodore Norvell
290

Como sugiere hippietrail , la respuesta de meder puede romper pares sustitutos y malinterpretar "personajes". Por ejemplo:

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

Sugiero usar una de las siguientes características de ES2015 para manejar correctamente estas secuencias de caracteres.

Sintaxis extendida ( ya respondida por insertusernamehere)

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

Array.from

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

uBandera RegExp

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

Usar en /(?=[\s\S])/ulugar de /(?=.)/uporque .no coincide con las nuevas líneas .

Si todavía está en la era ES5.1 (o si su navegador no maneja esta expresión regular correctamente, como Edge), puede usar esta alternativa (transpilada por Babel ):

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

Tenga en cuenta que Babel también trata de manejar sustitutos inigualables correctamente. Sin embargo, esto no parece funcionar para sustitutos bajos sin igual.

Prueba todo en tu navegador:

hakatashi
fuente
¿Cómo formaste estos personajes? Parece que cada carácter tiene 4 bytes.
user420667
2
@ user420667 los caracteres son de un plano de caracteres adicional (en la tabla Unicode) con puntos de código "grandes", por lo tanto, no caben en 16 bytes. La codificación utf-16 utilizada en javascript presenta estos caracteres como pares sustitutos (caracteres especiales que solo se usan como pares para formar otros caracteres a partir de planos adicionales). Solo los caracteres del plano principal se presentan con 16 bytes. Los caracteres especiales del par sustituto también son del plano del personaje principal, si tiene sentido.
Olga
1
El rendimiento de las diferentes técnicas , se extendió op parece el campeón (cromo 58).
Adrien
44
Tenga en cuenta que esta solución divide algunos emoji como 🏳️‍🌈, y divide la combinación de signos diacríticos de los personajes. Si desea dividirse en grupos de grafemas en lugar de caracteres, consulte stackoverflow.com/a/45238376 .
user202729
3
Tenga en cuenta que si bien no es bueno separar parejas sustitutas, no es una solución de propósito general para mantener unidos a los "personajes" (o más exactamente, los grafemas ). Un grafema puede estar compuesto por múltiples puntos de código; por ejemplo, el nombre del idioma Devanagari es "देवनागरी", que un hablante nativo lee como cinco grafemas, pero requiere ocho puntos de código para producir ...
TJ Crowder
71

La spreadsintaxis

Puede usar la sintaxis de propagación , un Array Initializer introducido en el estándar ECMAScript 2015 (ES6) :

var arr = [...str];

Ejemplos

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

Los primeros tres resultan en:

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

El último da como resultado

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

Soporte de navegador

Consulte la tabla de compatibilidad de ECMAScript ES6 .


Otras lecturas

spreadtambién se menciona como " splat" (por ejemplo, en PHP o Ruby o como " scatter" (por ejemplo, en Python ).


Manifestación

Probar antes de comprar

insertusernamehere
fuente
1
Si utiliza el operador de propagación en combinación con un compilador para ES5, esto no funcionará en IE. Toma eso en consideración. Me llevó horas descubrir cuál era el problema.
Stef van den Berg
14

También puedes usar Array.from.

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

Este método se ha introducido en ES6.

Referencia

Array.from

Rajesh
fuente
10

Esta es una vieja pregunta, pero encontré otra solución que aún no figura en la lista.

Puede usar la función Object.assign para obtener la salida deseada:

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

No necesariamente correcto o incorrecto, solo otra opción.

Object.assign se describe bien en el sitio MDN.

David Thomas
fuente
2
Eso es un largo camino para llegar Array.from("Hello, world").
TJ Crowder
@TJCrowder Eso es un largo camino para llegar[..."Hello, world"]
chharvey
@chharvey - Je. :-)
TJ Crowder
9

Ya es:

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

O para una versión anterior más amigable para el navegador, use:

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

dansimau
fuente
44
-1: no lo es. Pruébalo:alert("Hello world!" == ['H','e','l','l','o',' ','w','o','r','l','d'])
R. Martinho Fernandes
55
Lo siento. Supongo que lo que quise decir es: "puede acceder a caracteres individuales por referencia de índice como este sin crear una matriz de caracteres".
dansimau
3
No es confiable entre navegadores que no puedes. Es una característica de la quinta edición de ECMAScript.
bobince
8
La versión de navegador cruzado es mystring.charAt(index).
psmay
1
+1 para - charAt()aunque preferiría usar la variante array-ish. Maldición IE.
Zenexer
4

Hay (al menos) tres cosas diferentes que podría concebir como un "personaje" y, en consecuencia, tres categorías diferentes de enfoque que puede utilizar.

División en unidades de código UTF-16

Las cadenas de JavaScript se inventaron originalmente como secuencias de unidades de código UTF-16, en un punto de la historia cuando había una relación uno a uno entre las unidades de código UTF-16 y los puntos de código Unicode. La .lengthpropiedad de una cadena mide su longitud en unidades de código UTF-16, y cuando lo hace someString[i], obtiene la i ª unidad de código UTF-16 desomeString .

En consecuencia, puede obtener una matriz de unidades de código UTF-16 de una cadena utilizando un bucle for de estilo C con una variable de índice ...

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

También hay varias formas cortas de lograr lo mismo, como usar .split()con la cadena vacía como separador:

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

Sin embargo, si su cadena contiene puntos de código que están formados por múltiples unidades de código UTF-16, esto los dividirá en unidades de código individuales, que pueden no ser lo que desea. Por ejemplo, la cadena '𝟘𝟙𝟚𝟛'se compone de cuatro puntos de código unicode (puntos de código 0x1D7D8 a 0x1D7DB) que, en UTF-16, están formados por dos unidades de código UTF-16. Si dividimos esa cadena usando los métodos anteriores, obtendremos una matriz de ocho unidades de código:

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

División en puntos de código Unicode

Entonces, ¡tal vez queremos dividir nuestra cadena en puntos de código Unicode! Eso ha sido posible desde que ECMAScript 2015 agregó el concepto de un iterable al lenguaje. Las cadenas ahora son iterables, y cuando iteras sobre ellas (por ejemplo, con un for...ofbucle), obtienes puntos de código Unicode, no unidades de código UTF-16:

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

Podemos acortar este uso Array.from, que itera sobre el iterable que se pasa implícitamente:

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

Sin embargo, los puntos de código Unicode no son los más grandes que sea posible que, posiblemente, podría ser considerado un "carácter" o bien . Algunos ejemplos de cosas que razonablemente podrían considerarse un solo "personaje" pero que se componen de múltiples puntos de código incluyen:

  • Caracteres acentuados, si el acento se aplica con un punto de código combinado
  • Banderas
  • Algunos emojis

Podemos ver a continuación que si intentamos convertir una cadena con tales caracteres en una matriz a través del mecanismo de iteración anterior, los caracteres terminan divididos en la matriz resultante. (En caso de que alguno de los caracteres no aparezca en su sistema, a yourStringcontinuación se incluye una A mayúscula con un acento agudo, seguida de la bandera del Reino Unido, seguida de una mujer negra).

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

Si queremos mantener cada uno de estos como un solo elemento en nuestro conjunto final, entonces necesitamos un conjunto de grafemas , no puntos de código.

Dividirse en grafemas

JavaScript no tiene soporte incorporado para esto, al menos no todavía. Por lo tanto, necesitamos una biblioteca que comprenda e implemente las reglas Unicode sobre qué combinación de puntos de código constituye un grafema. Afortunadamente, existe uno: el divisor de grafemas de Orling . Querrá instalarlo con npm o, si no está usando npm, descargue el archivo index.js y sirva con una <script>etiqueta. Para esta demostración, la cargaré desde jsDelivr.

grafema-divisor nos da una GraphemeSplitterclase con tres métodos: splitGraphemes, iterateGraphemes, y 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>

Y ahí estamos: una serie de tres grafemas, que es probablemente lo que querías.

Mark Amery
fuente
2

Puede iterar sobre la longitud de la cadena y empujar el carácter en cada posición :

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
fuente
1
Si bien este enfoque es un poco más imperativo que declarativo, es el más eficaz de todos en este hilo y merece más amor. Una limitación para recuperar un carácter en una cadena por posición es cuando se trata de caracteres más allá del Plan Multilingüe Básico en unicode como los emojis. "😃".charAt(0)devolverá un personaje inutilizable
KyleMit
2
@KyleMit esto solo parece cierto para una entrada corta. Usar una entrada más larga vuelve a ser .split("")la opción más rápida
Lux
1
También .split("")parece estar muy optimizado en Firefox. Si bien el bucle tiene un rendimiento similar en Chrome y Firefox, la división es significativamente más rápida en Firefox para entradas pequeñas y grandes.
Lux
2

respuesta simple:

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

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

ajit kumar
fuente
-1; esto no agrega nada que no haya sido incluido en la respuesta de hakatashi .
Mark Amery
0

Una posibilidad es la siguiente:

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(''));
usuario2301515
fuente
-1

¿Qué tal esto?

function stringToArray(string) {
  let length = string.length;
  let array = new Array(length);
  while (length--) {
    array[length] = string[length];
  }
  return array;
}
msand
fuente
@KyleMit esto parece más rápido que para i loop + push jsperf.com/string-to-character-array/3
msand