Come si ottiene una stringa in una matrice di caratteri in JavaScript?


370

Come si converte una stringa in una matrice di caratteri in JavaScript?

Sto pensando di ottenere una stringa simile "Hello world!"all'array
['H','e','l','l','o',' ','w','o','r','l','d','!']

Risposte:


493

Nota: questo non è conforme agli Unicode. "I💖U".split('')genera un array di 4 caratteri ["I", "�", "�", "u"]che può portare a bug pericolosi. Vedi le risposte di seguito per alternative sicure.

Basta dividerlo per una stringa vuota.

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

Vedi i String.prototype.split()documenti MDN .


31
Questo non tiene conto delle coppie surrogate. "𨭎".split('')risultati in ["�", "�"].
hippietrail,

59
Vedi la risposta di @ hakatashi altrove in questa discussione. Spero che tutti lo vedano ... NON UTILIZZARE QUESTO METODO, NON È UNICODE SICURO
i336_

3
Un po 'tardi alla festa. Ma perché qualcuno dovrebbe mai voler creare una matrice di una stringa? Una stringa è già un array o sbaglio? "randomstring".length; //12 "randomstring"[2]; //"n"
Luigi van der Pal

4
@LuigivanderPal Una stringa non è un array, ma è molto simile. Tuttavia, non è simile a una matrice di caratteri. Una stringa è simile a una matrice di numeri a 16 bit, alcuni dei quali rappresentano caratteri e alcuni rappresentano la metà di una coppia surrogata. Ad esempio, str.lengthnon indica il numero di caratteri nella stringa, poiché alcuni caratteri occupano più spazio di altri; str.lengthti dice il numero di numeri a 16 bit.
Theodore Norvell,

290

Come suggerisce hippietrail , la risposta del mediatore può rompere le coppie surrogate e interpretare erroneamente i "personaggi". Per esempio:

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

Suggerisco di utilizzare una delle seguenti funzioni ES2015 per gestire correttamente queste sequenze di caratteri.

Sintassi diffusa ( già risposta con insertusernamehere)

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

Array.from

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

uFlag RegExp

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

Utilizzare /(?=[\s\S])/uinvece di /(?=.)/uperché .non corrisponde alle nuove righe .

Se sei ancora nell'era ES5.1 (o se il tuo browser non gestisce correttamente questa regex - come Edge), puoi usare questa alternativa (tradotta da Babel ):

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

Si noti che Babele cerca anche di gestire correttamente surrogati senza pari. Tuttavia, questo non sembra funzionare per surrogati bassi senza eguali.

Prova tutto nel tuo browser:


Come hai formato questi personaggi? Sembra che ogni personaggio sia di 4 byte.
user420667,

2
@ user420667 i caratteri provengono da un piano di caratteri aggiuntivo (nella tabella unicode) con punti di codice "grandi", pertanto non si adattano a 16 byte. La codifica utf-16 utilizzata in JavaScript presenta questi caratteri come coppie surrogate (caratteri speciali che vengono utilizzati solo come coppie per formare altri caratteri da piani aggiuntivi). Solo i personaggi sul piano principale del personaggio sono presentati con 16 byte. Anche i caratteri speciali della coppia di coniugi Surrugate provengono dal piano del personaggio principale, se risulta utile.
Olga,

1
Prestazioni delle diverse tecniche , l'op di diffusione sembra il campione (cromo 58).
Adrien,

4
Nota che questa soluzione divide alcune emoji come 🏳️‍🌈, e si divide combinando segni diacritici dai personaggi. Se si desidera suddividere in cluster grapheme anziché caratteri, consultare stackoverflow.com/a/45238376 .
user202729

3
Si noti che pur non dividendo le coppie surrogate è grandioso, non è una soluzione generica per tenere insieme "personaggi" (o, più precisamente, grafemi ). Un grafema può essere composto da più punti di codice; per esempio, il nome della lingua Devanagari è "देवनागरी", che viene letto da un madrelingua come cinque grafemi, ma prende otto punti in codice per produrre ...
TJ Crowder,

71

La spreadsintassi

È possibile utilizzare la sintassi di diffusione , un inizializzatore di array introdotto nello standard ECMAScript 2015 (ES6) :

var arr = [...str];

Esempi

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

I primi tre risultati in:

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

L'ultimo risulta in

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

Supporto per il browser

Controllare la tabella di compatibilità ECMAScript ES6 .


Ulteriori letture

spreadviene anche indicato come " splat" (ad esempio in PHP o Ruby o come " scatter" (ad esempio in Python ).


dimostrazione

Prova prima di acquistare


1
Se si utilizza l'operatore spread in combinazione con un compilatore per ES5, questo non funzionerà in IE. Prendilo in considerazione. Mi ci sono volute ore per capire quale fosse il problema.
Stef van den Berg,

14

Puoi anche usare Array.from.

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

Questo metodo è stato introdotto in ES6.

Riferimento

Array.from


10

Questa è una vecchia domanda ma mi sono imbattuto in un'altra soluzione non ancora elencata.

È possibile utilizzare la funzione Object.assign per ottenere l'output desiderato:

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

Non necessariamente giusto o sbagliato, solo un'altra opzione.

Object.assign è ben descritto nel sito MDN.


2
Questa è una lunga strada da percorrere Array.from("Hello, world").
TJ Crowder,

@TJCrowder Questa è una lunga strada da percorrere[..."Hello, world"]
chharvey,

@chharvey - Heh. :-)
TJ Crowder,

9

È già:

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

O per una versione più vecchia del browser, utilizzare:

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


4
-1: non lo è. Prova:alert("Hello world!" == ['H','e','l','l','o',' ','w','o','r','l','d'])
R. Martinho Fernandes,

5
Scusate. Immagino che ciò che intendevo dire è: "puoi accedere a singoli caratteri mediante un indice di riferimento come questo senza creare una matrice di caratteri".
dansimau,

3
Non è possibile eseguire il cross-browser in modo affidabile. È una funzione della quinta edizione di ECMAScript.
bobince,

8
La versione cross-browser è mystring.charAt(index).
psmay

1
+1 per charAt()- anche se preferirei usare la variante array-ish. Darn IE.
Zenexer,

4

Ci sono (almeno) tre cose diverse che potresti concepire come un "personaggio" e, di conseguenza, tre diverse categorie di approccio che potresti voler usare.

Suddivisione in unità di codice UTF-16

Le stringhe JavaScript sono state originariamente inventate come sequenze di unità di codice UTF-16, in un punto della storia in cui esisteva una relazione uno a uno tra unità di codice UTF-16 e punti di codice Unicode. La .lengthproprietà di una stringa misura la sua lunghezza in unità UTF-16 del codice, e quando lo fai someString[i]si ottiene il I ° UTF-16 unità di codicesomeString .

Di conseguenza, è possibile ottenere una matrice di unità di codice UTF-16 da una stringa utilizzando un for-loop in stile C con una variabile indice ...

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

Esistono anche diversi modi per ottenere la stessa cosa, come usare .split()con la stringa vuota come separatore:

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

Tuttavia, se la stringa contiene punti di codice costituiti da più unità di codice UTF-16, ciò li suddividerà in singole unità di codice, che potrebbero non essere quelle desiderate. Ad esempio, la stringa '𝟘𝟙𝟚𝟛'è composta da quattro punti di codice unicode (punti di codice da 0x1D7D8 a 0x1D7DB) che, in UTF-16, sono ciascuno composto da due unità di codice UTF-16. Se dividiamo quella stringa usando i metodi sopra, otterremo una matrice di otto unità di codice:

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

Suddivisione in punti di codice Unicode

Quindi, forse vogliamo invece dividere la nostra stringa in punti di codice Unicode! Questo è stato possibile da quando ECMAScript 2015 ha aggiunto il concetto di iterabile alla lingua. Le stringhe ora sono iterabili e quando si esegue l'iterazione su di esse (ad es. Con un for...ofciclo), si ottengono punti di codice Unicode, non unità di codice UTF-16:

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

Possiamo abbreviare questo usando Array.from, che scorre sull'iterabile che è passato implicitamente:

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

Tuttavia, punti di codice Unicode non sono il più grande cosa possibile che potrebbe essere considerato un "carattere" o . Alcuni esempi di cose che potrebbero ragionevolmente essere considerati un singolo "carattere" ma che possono essere costituiti da più punti di codice includono:

  • Caratteri accentati, se l'accento è applicato con un punto di codice combinato
  • bandiere
  • Alcuni emoji

Di seguito possiamo vedere che se proviamo a convertire una stringa con tali caratteri in un array tramite il meccanismo di iterazione sopra, i caratteri vengono suddivisi nell'array risultante. (Nel caso in cui uno dei personaggi non venga visualizzato sul tuo sistema, di yourStringseguito è presente una A maiuscola con un accento acuto, seguita dalla bandiera del Regno Unito, seguita da una donna di colore.)

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

Se vogliamo mantenere ognuno di questi come un singolo oggetto nel nostro array finale, allora abbiamo bisogno di un array di grafemi , non di punti di codice.

Suddivisione in grafemi

JavaScript non ha supporto integrato per questo - almeno non ancora. Quindi abbiamo bisogno di una libreria che comprenda e implementi le regole Unicode per quale combinazione di punti di codice costituisce un grafo. Fortunatamente ne esiste uno: il frammento di grafema di Orling . Ti consigliamo di installarlo con npm o, se non stai utilizzando npm, scarica il file index.js e servilo con un <script>tag. Per questa demo, lo caricherò da jsDelivr.

grafema-splitter ci dà una GraphemeSplitterclasse con tre metodi: splitGraphemes, iterateGraphemes, e countGraphemes. Naturalmente, vogliamo splitGraphemes:

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

Ed eccoci qui - una schiera di tre grafemi, che è probabilmente quello che volevi.


2

Puoi iterare sulla lunghezza della stringa e spingere il carattere in ogni posizione :

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


1
Mentre questo approccio è un po 'più imperativo che dichiarativo, è il più performante di tutti in questo thread e merita più amore. Una limitazione al recupero di un personaggio su una stringa per posizione è quando si ha a che fare con personaggi oltre il Piano multilingue di base in unicode come emoji. "😃".charAt(0)restituirà un personaggio inutilizzabile
KyleMit,

2
@KyleMit questo sembra vero solo per un breve input. L'uso di un input più lungo rende di .split("")nuovo l'opzione più veloce
Lux

1
.split("")Sembra anche essere fortemente ottimizzato in Firefox. Mentre il loop ha prestazioni simili in Chrome e Firefox diviso è significativamente più veloce in Firefox per input piccoli e grandi.
Lux


0

Una possibilità è la prossima:

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

-1

Cosa ne pensi di questo?

function stringToArray(string) {
  let length = string.length;
  let array = new Array(length);
  while (length--) {
    array[length] = string[length];
  }
  return array;
}

@KyleMit questo sembra più veloce che per i loop + push jsperf.com/string-to-character-array/3
ms

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.