Jak uzyskać ciąg do tablicy znaków w JavaScript?


369

Jak przekonwertować ciąg na tablicę znaków w JavaScript?

Myślę, że otrzymam ciąg podobny "Hello world!"do tablicy
['H','e','l','l','o',' ','w','o','r','l','d','!']

Odpowiedzi:


492

Uwaga: To nie jest zgodne z Unicode. "I💖U".split('')skutkuje tablicą 4 znaków, ["I", "�", "�", "u"]która może prowadzić do niebezpiecznych błędów. Zobacz odpowiedzi poniżej, aby uzyskać bezpieczne alternatywy.

Po prostu podziel go pustym ciągiem.

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

Zobacz String.prototype.split()dokumenty MDN .


31
Nie bierze to pod uwagę par zastępczych. "𨭎".split('')powoduje w ["�", "�"].
hippietrail

59
Zobacz odpowiedź @ hakatashi w innym miejscu tego wątku. Mam nadzieję, że wszyscy to widzą ... NIE UŻYWAJ TEJ METODY, TO NIE JEST BEZPIECZNE
i336_

3
Trochę późno na imprezę. Ale dlaczego ktoś miałby chcieć stworzyć tablicę łańcucha? Ciąg jest już tablicą, czy się mylę? "randomstring".length; //12 "randomstring"[2]; //"n"
Luigi van der Pal

4
@LuigivanderPal Ciąg nie jest tablicą, ale jest bardzo podobny. Jednak nie jest podobny do tablicy znaków. Ciąg jest podobny do tablicy 16-bitowych liczb, z których niektóre reprezentują znaki, a niektóre reprezentują połowę pary zastępczej. Na przykład str.lengthnie podaje liczby znaków w ciągu, ponieważ niektóre znaki zajmują więcej miejsca niż inne; str.lengthpodaje liczbę liczb 16-bitowych.
Theodore Norvell,

289

Jak sugeruje hippietrail , odpowiedź medera może rozbijać pary zastępcze i błędnie interpretować „postacie”. Na przykład:

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

Sugeruję użycie jednej z następujących funkcji ES2015, aby poprawnie obsługiwać te sekwencje znaków.

Rozkładanie składni ( odpowiedź już wstawiona przez inserttusernamehere)

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

Array.from

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

uFlaga RegExp

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

Użyj /(?=[\s\S])/uzamiast, /(?=.)/uponieważ .nie pasuje do nowych linii .

Jeśli nadal jesteś w erze ES5.1 (lub jeśli Twoja przeglądarka nie obsługuje poprawnie tego wyrażenia regularnego - takiego jak Edge), możesz użyć tej alternatywy (transpilowanej przez Babel ):

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

Zauważ, że Babel próbuje również poprawnie obsługiwać niedopasowane parametry zastępcze. Nie wydaje się to jednak działać w przypadku niedopasowanych niskich surogatów.

Przetestuj wszystko w przeglądarce:


Jak uformowałeś te postacie? Wygląda na to, że każdy znak ma 4 bajty.
user420667

2
@ user420667 znaki pochodzą z dodatkowej płaszczyzny znaków (w tabeli unicode) z „dużymi” punktami kodowymi, dlatego nie mieszczą się w 16 bajtach. Kodowanie utf-16 użyte w javascript przedstawia te znaki jako pary zastępcze (znaki specjalne, które są używane tylko jako pary do tworzenia innych znaków z dodatkowych płaszczyzn). Tylko znaki z głównej płaszczyzny postaci są przedstawiane z 16 bajtami. Znaki specjalne pary falistej pochodzą również z płaszczyzny głównej postaci, jeśli się pojawi.
Olga,

1
Wydajność różnych technik , spread op wygląda jak mistrz (chrom 58).
Adrien

4
Zauważ, że to rozwiązanie dzieli niektóre emoji, takie jak 🏳️‍🌈i dzieli znak diakrytyczny od znaków. Jeśli chcesz podzielić na klastry grafem zamiast znaków, zobacz stackoverflow.com/a/45238376 .
user202729,

3
Pamiętaj, że chociaż nie rozbijanie par zastępczych jest świetne, nie jest to rozwiązanie ogólnego zastosowania do utrzymywania razem „postaci” (a ściślej grafemów ). Grafem może być wiele punktów kodowych; na przykład nazwa języka Devanagari to „देवनागरी”, którą native speaker odczytuje jako pięć grafemów, ale do wygenerowania używa ośmiu punktów kodowych ...
TJ Crowder

71

spreadSkładnia

Możesz użyć składni stron widzących , inicjatora macierzy wprowadzonego w standardzie ECMAScript 2015 (ES6) :

var arr = [...str];

Przykłady

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

Pierwsze trzy wynik to:

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

Ostatni powoduje

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

Obsługa przeglądarki

Sprawdź tabelę zgodności ECMAScript ES6 .


Dalsza lektura

spreadjest również określany jako „ splat” (np. w PHP lub Ruby lub jako „ scatter” (np. w Pythonie ).


Próbny

Wypróbuj przed zakupem


1
Jeśli używasz operatora spreadu w połączeniu z kompilatorem do ES5, to nie będzie działać w IE. Weź to pod uwagę. Zrozumienie, na czym polegał problem, zajęło mi wiele godzin.
Stef van den Berg


10

To stare pytanie, ale natknąłem się na inne rozwiązanie jeszcze nie wymienione.

Możesz użyć funkcji Object.assign, aby uzyskać pożądany wynik:

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

Niekoniecznie dobre lub złe, tylko inna opcja.

Object.assign jest dobrze opisany na stronie MDN.


2
To długa droga do przebycia Array.from("Hello, world").
TJ Crowder,

@TJCrowder To długa droga do osiągnięcia[..."Hello, world"]
chharvey

@chharvey - Heh. :-)
TJ Crowder

9

To już jest:

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

Lub w przypadku starszej wersji przyjaznej dla przeglądarki użyj:

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


4
-1: nie jest. Spróbuj:alert("Hello world!" == ['H','e','l','l','o',' ','w','o','r','l','d'])
R. Martinho Fernandes

4
Przepraszam. Wydaje mi się, że chciałem powiedzieć: „możesz uzyskać dostęp do poszczególnych znaków za pomocą odwołania do indeksu w ten sposób bez tworzenia tablicy znaków”.
dansimau

3
Nie niezawodnie w różnych przeglądarkach nie możesz. Jest to funkcja ECMAScript Piąta edycja.
Bobin

8
Wersja dla różnych przeglądarek to mystring.charAt(index).
psmay

1
+1 za - charAt()choć wolałbym użyć wariantu tablicowego. Darn IE.
Zenexer

4

Istnieją (co najmniej) trzy różne rzeczy, które możesz postrzegać jako „postać”, aw konsekwencji trzy różne kategorie podejścia, które możesz chcieć zastosować.

Podział na jednostki kodu UTF-16

Ciągi JavaScript zostały pierwotnie wynalezione jako sekwencje jednostek kodu UTF-16, w pewnym momencie historii, kiedy istniała relacja jeden-do-jednego między jednostkami kodu UTF-16 a punktami kodu Unicode. .lengthWłasnością łańcucha mierzy jego długość w jednostkach UTF-16 kodowych, a kiedy to zrobisz someString[i]dostaniesz I th UTF-16 jednostki kodusomeString .

W związku z tym możesz uzyskać tablicę jednostek kodu UTF-16 z ciągu, używając pętli for w stylu C ze zmienną indeksową ...

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

Istnieją również różne krótkie sposoby osiągnięcia tego samego, na przykład użycie .split()pustego łańcucha jako separatora:

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

Jeśli jednak ciąg zawiera punkty kodowe złożone z wielu jednostek kodu UTF-16, spowoduje to podzielenie ich na poszczególne jednostki kodu, co może nie być tym, czego chcesz. Na przykład ciąg znaków '𝟘𝟙𝟚𝟛'składa się z czterech punktów kodu Unicode (punkty kodu od 0x1D7D8 do 0x1D7DB), które w UTF-16 składają się z dwóch jednostek kodu UTF-16. Jeśli podzielimy ten ciąg przy użyciu powyższych metod, otrzymamy tablicę ośmiu jednostek kodu:

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

Podział na punkty kodu Unicode

Być może chcemy zamiast tego podzielić nasz ciąg znaków na punkty kodowe Unicode! Było to możliwe, ponieważ ECMAScript 2015 dodał koncepcję iteracji do języka. Ciągi są teraz iterowalne, a gdy iterujesz nad nimi (np. Za pomocą for...ofpętli), otrzymujesz punkty kodu Unicode, a nie jednostki kodu UTF-16:

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

Możemy skrócić to, używając Array.fromiteracji w stosunku do iterowności, która została przekazana niejawnie:

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

Jednak punkty kodu Unicode nie są największą możliwą rzeczą, którą można by uznać za „znak” albo . Niektóre przykłady rzeczy, które można rozsądnie uznać za pojedynczy „znak”, ale składać się z wielu punktów kodowych, obejmują:

  • Znaki akcentowane, jeśli akcent jest stosowany z łączącym punktem kodowym
  • Flagi
  • Niektóre emoji

Widzimy poniżej, że jeśli spróbujemy przekonwertować ciąg z takimi znakami na tablicę za pomocą powyższego mechanizmu iteracji, znaki zostaną podzielone na wynikową tablicę. (W przypadku, gdy żadna z postaci nie renderuje się w twoim systemie, yourStringponiżej składa się z dużej litery A z ostrym akcentem, po której następuje flaga Wielkiej Brytanii, a następnie czarna kobieta).

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

Jeśli chcemy zachować każdy z nich jako pojedynczy element w końcowej tablicy, potrzebujemy tablicy grafemów , a nie punktów kodowych.

Podział na grafemy

JavaScript nie ma wbudowanej obsługi tego - przynajmniej jeszcze nie. Potrzebujemy więc biblioteki, która rozumie i implementuje reguły Unicode dla tego, która kombinacja punktów kodowych stanowi grafem. Na szczęście, jeden istnieje: orling jest grafem-splitter . Będziesz chciał zainstalować go z npm lub, jeśli nie używasz npm, pobierz plik index.js i podaj go ze <script>znacznikiem. W tym demo załaduję go z jsDelivr.

grafem-splitter daje nam GraphemeSplitterlekcje z trzech metod: splitGraphemes, iterateGraphemes, i countGraphemes. Oczywiście chcemy 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>

I oto jesteśmy - tablica trzech grafemów, prawdopodobnie tego właśnie chciałeś.


2

Możesz iterować na całej długości łańcucha i przesuwać znak w każdej pozycji :

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
Chociaż takie podejście jest nieco bardziej konieczne niż deklaratywne, jest najbardziej wydajne ze wszystkich w tym wątku i zasługuje na więcej miłości. Jedynym ograniczeniem do pobierania znak na sznurku przez położenie jest gdy ma do czynienia z postaciami minionych z podstawowego planu Multilingual w Unicode, takie jak emotikony. "😃".charAt(0)zwróci postać bezużyteczną
KyleMit

2
@KyleMit wydaje się to prawdą tylko w przypadku krótkich danych wejściowych. Korzystanie z dłuższych danych wejściowych ponownie powoduje .split("")najszybszą opcję
Lux

1
Również .split("")wydaje się być mocno zoptymalizowany w Firefoksie. Podczas gdy pętla ma podobną wydajność w dzieleniu chrome i firefox, jest znacznie szybsza w firefoxie dla małych i dużych danych wejściowych.
Lux


0

Jedna z możliwości jest następna:

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

Co powiesz na to?

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

@KyleMit wydaje się to szybsze niż dla pętli i + push jsperf.com/string-to-character-array/3
msand

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.