Как вы получаете строку в массив символов в JavaScript?

371

Как преобразовать строку в массив символов в JavaScript?

Я думаю получить строку, как "Hello world!"в массив
['H','e','l','l','o',' ','w','o','r','l','d','!']

DarkLightA
источник

Ответы:

494

Примечание. Это не соответствует юникоду. "I💖U".split('')приводит к массиву из 4 символов, ["I", "�", "�", "u"]который может привести к опасным ошибкам. Смотрите ответы ниже для безопасных альтернатив.

Просто разделите его на пустую строку.

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

Смотрите String.prototype.split()MDN документы .

медер омуралиев
источник
31
Это не учитывает суррогатных пар. "𨭎".split('')результаты в ["�", "�"].
hippietrail
59
Смотрите ответ @ hakatashi в другом месте этой темы. Надеюсь, все видят это ... НЕ ИСПОЛЬЗУЙТЕ ЭТОТ МЕТОД, ЭТО НЕ
ЮНИКОД
3
Немного опоздал на вечеринку. Но почему кто-то хочет создать массив из строки? Строка уже массив или я не прав? "randomstring".length; //12 "randomstring"[2]; //"n"
Луиджи ван дер Пал
4
@LuigivanderPal Строка не является массивом, но она очень похожа. Однако это не похоже на массив символов. Строка похожа на массив 16-битных чисел, некоторые из которых представляют символы, а некоторые представляют половину суррогатной пары. Например, str.lengthне сообщает вам количество символов в строке, поскольку некоторые символы занимают больше места, чем другие; str.lengthговорит вам количество 16-битных чисел.
Теодор Норвелл
291

Как hippietrail предполагает , ответ Meder в может нарушить суррогатные пары и извращают «символы.» Например:

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

Я предлагаю использовать одну из следующих функций ES2015, чтобы правильно обрабатывать эти последовательности символов.

Синтаксис распространения ( уже ответил на имя пользователя вставки здесь)

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

Array.from

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

uФлаг RegExp

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

Используйте /(?=[\s\S])/uвместо, /(?=.)/uпотому .что не совпадает с символами новой строки .

Если вы все еще находитесь в эпохе ES5.1 (или если ваш браузер неправильно обрабатывает это регулярное выражение - например, Edge), вы можете использовать эту альтернативу (предоставлено Babel ):

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

Обратите внимание, что Вавилон пытается правильно обрабатывать непревзойденных суррогатов. Однако, это, кажется, не работает для непревзойденных низких суррогатов.

Протестируйте все в вашем браузере:

hakatashi
источник
Как вы сформировали этих персонажей? Похоже, каждый символ занимает 4 байта.
user420667
2
@ user420667 символы из дополнительной символьной плоскости (в таблице юникода) с "большими" кодовыми точками, поэтому они не помещаются в 16 байтов. Кодировка utf-16, используемая в javascript, представляет эти символы как суррогатные пары (специальные символы, которые используются только как пары для формирования других символов из дополнительных плоскостей). Только символы основной плоскости персонажа представлены 16 байтами. Пара дополнительных символов Surrugate также из основной плоскости персонажа, если это имеет смысл.
Ольга
1
По исполнению различных техник , распространение op выглядит как чемпион (chrome 58).
Адриен
4
Обратите внимание, что это решение разделяет некоторые эмодзи, такие как 🏳️‍🌈, и разделяет объединяющую диакритическую метку от символов. Если вы хотите разбить кластеры графем вместо символов, см. Stackoverflow.com/a/45238376 .
user202729
3
Обратите внимание, что хотя разделение суррогатных пар - это замечательно, это не универсальное решение для хранения «символов» (или, точнее, графем ) вместе. Графема может состоять из нескольких кодовых точек; например, название языка деванагари - «देवनागरी», которое носитель языка читает как пять графем, но для его создания требуется восемь кодовых точек ...
TJ Crowder
71

spreadСинтаксис

Вы можете использовать синтаксис распространения , инициализатор массива, представленный в стандарте ECMAScript 2015 (ES6) :

var arr = [...str];

Примеры

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

Первые три результата в:

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

Последний результат в

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

Поддержка браузера

Проверьте таблицу совместимости ECMAScript ES6 .


дальнейшее чтение

spreadтакже упоминается как " splat" (например, в PHP или Ruby или как " scatter" (например, в Python ).


демонстрация

Попробуй перед покупкой

insertusernamehere
источник
1
Если вы используете оператор распространения в сочетании с компилятором для ES5, то это не будет работать в IE. Примите это во внимание. Мне потребовались часы, чтобы понять, в чем проблема.
Стеф ван ден Берг
14

Вы также можете использовать Array.from.

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

Этот метод был введен в ES6.

Ссылка

Array.from

Раджеш
источник
10

Это старый вопрос, но я столкнулся с другим решением, которого пока нет в списке.

Вы можете использовать функцию Object.assign, чтобы получить желаемый результат:

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

Не обязательно правильно или неправильно, просто другой вариант.

Object.assign хорошо описан на сайте MDN.

Дэвид Томас
источник
2
Это долгий путь, чтобы добраться до Array.from("Hello, world").
TJ Crowder
@TJCrowder Это долгий путь, чтобы добраться до[..."Hello, world"]
chharvey
@chharvey - Хех. :-)
TJ Crowder
9

Это уже есть:

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

Или для более старой версии, удобной для браузера, используйте:

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

dansimau
источник
4
-1: нет Попробуйте:alert("Hello world!" == ['H','e','l','l','o',' ','w','o','r','l','d'])
Р. Мартиньо Фернандес
5
Сожалею. Я думаю, что я хотел сказать так: «Вы можете получить доступ к отдельным символам, используя указатель индекса, без создания массива символов».
dansimau
3
Не надежно кросс-браузер вы не можете. Это функция пятого издания ECMAScript.
bobince
8
Кросс-браузерная версия есть mystring.charAt(index).
psmay
1
+1 за - charAt()хотя я бы предпочел использовать вариант массива. Штопать IE.
Zenexer
4

Есть (по крайней мере) три разные вещи, которые вы можете рассматривать как «персонажа», и, следовательно, три разных категории подхода, которые вы можете использовать.

Разбиение на кодовые единицы UTF-16

Строки JavaScript изначально были изобретены как последовательности единиц кода UTF-16, еще в истории, когда существовала взаимно-однозначная связь между единицами кода UTF-16 и кодовыми точками Unicode. .lengthСвойство строки измеряет длину в UTF-16 единиц коды, и когда вы делаете someString[i]вы получаете I - й UTF-16 код единицы someString.

Следовательно, вы можете получить массив кодовых блоков UTF-16 из строки, используя цикл for в стиле C с индексной переменной ...

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

Существуют также различные короткие способы достижения того же, например, использование .split()пустой строки в качестве разделителя:

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

Однако, если ваша строка содержит кодовые точки, которые состоят из нескольких кодовых блоков UTF-16, это разделит их на отдельные кодовые блоки, что может оказаться не тем, что вам нужно. Например, строка '𝟘𝟙𝟚𝟛'состоит из четырех кодовых точек Unicode (кодовые точки от 0x1D7D8 до 0x1D7DB), каждая из которых в UTF-16 состоит из двух кодовых блоков UTF-16. Если мы разделим эту строку, используя методы выше, мы получим массив из восьми единиц кода:

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

Разделение на кодовые точки Unicode

Так что, возможно, мы хотим вместо этого разделить нашу строку на Unicode Code Points! Это стало возможным с тех пор, как в ECMAScript 2015 была добавлена ​​концепция итерируемого языка. Строки теперь итерируемые, и когда вы перебираете их (например, с помощью for...ofцикла), вы получаете кодовые точки Unicode, а не единицы кода UTF-16:

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

Мы можем сократить это, используя Array.fromитерацию для итерируемого, который он передается неявно:

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

Однако Юникод кодовых точки не самое большое, что могло возможно считать «характер» либо . Некоторые примеры вещей, которые можно разумно рассматривать как один «символ», но которые состоят из нескольких кодовых точек, включают:

  • Символы с ударением, если ударение применяется с комбинированной кодовой точкой
  • Флаги
  • Некоторые смайлики

Ниже мы увидим, что если мы попытаемся преобразовать строку с такими символами в массив с помощью механизма итерации, описанного выше, символы будут разбиты в результирующем массиве. (В случае, если какой-либо из персонажей не отображается в вашей системе, yourStringниже представлена ​​заглавная буква A с острым акцентом, за которой следует флаг Соединенного Королевства, за которым следует чернокожая женщина.)

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

Если мы хотим сохранить каждый из них как один элемент в нашем конечном массиве, то нам нужен массив графем , а не кодовые точки.

Расщепление на графемы

JavaScript не имеет встроенной поддержки для этого - по крайней мере, пока. Поэтому нам нужна библиотека, которая понимает и реализует правила Unicode, для которых комбинация кодовых точек составляет графему. К счастью, существует одно: графем-сплиттер Орлинга . Вы можете установить его с помощью npm или, если вы не используете npm, загрузить файл index.js и использовать его с <script>тегом. Для этой демонстрации я буду загружать ее из jsDelivr.

графема-разветвитель дает нам GraphemeSplitterкласс с тремя методами: splitGraphemes, iterateGraphemesи countGraphemes. Естественно, мы хотим 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>

И вот мы - массив из трех графем, что, вероятно, то, что вы хотели.

Марк Эмери
источник
2

Вы можете перебрать всю длину строки и нажать символ в каждой позиции :

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
Хотя этот подход немного более обязателен, чем декларативный, он наиболее эффективен среди всех в этой теме и заслуживает большей любви. Одно ограничение для извлечения символа в строке по позиции - это когда он работает с символами после Базового многоязычного плана в юникоде, такими как смайлики. "😃".charAt(0)вернет непригодного персонажа
KyleMit
2
@KyleMit это кажется верным только для короткого ввода. Использование более длинного ввода .split("")снова делает самый быстрый вариант
Lux
1
Также, .split("")кажется, сильно оптимизирован в Firefox. Хотя цикл имеет одинаковую производительность в Chrome и Firefox, он значительно быстрее в Firefox для малых и больших входов.
Люкс
0

Одна возможность заключается в следующем:

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
источник
-1

Как насчет этого?

function stringToArray(string) {
  let length = string.length;
  let array = new Array(length);
  while (length--) {
    array[length] = string[length];
  }
  return array;
}
msand
источник
@KyleMit это кажется быстрее, чем для I loop + push jsperf.com/string-to-character-array/3
msand