Як отримати рядок до масиву символів у JavaScript?


369

Як перетворити рядок у масив символів у JavaScript?

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

Відповіді:


492

Примітка. Це не сумісно з unicode. "I💖U".split('')призводить до 4-символьного масиву, ["I", "�", "�", "u"]який може призвести до небезпечних помилок. Дивіться відповіді нижче щодо безпечних альтернатив.

Просто розділіть його порожнім рядком.

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

Див. String.prototype.split()Документи MDN .


31
Це не враховує сурогатних пар. "𨭎".split('')результати в ["�", "�"].
hippietrail

59
Дивіться відповідь @ hakatashi в іншому місці цього потоку. Сподіваємось, всі це бачать ... НЕ ВИКОРИСТОВУЮТЬ ЦІЙ МЕТОД, НЕ БЕЗПЕЧНИЙ БЕЗПЕЧНИЙ
i336_

3
Трохи спізнившись на вечірку. Але чому хтось хотів би колись створити масив рядків? Рядок - це вже масив чи я помиляюся? "randomstring".length; //12 "randomstring"[2]; //"n"
Луїджі ван дер Пал

4
@LuigivanderPal Рядок - це не масив, але він дуже схожий. Однак він не схожий на масив символів. Рядок схожий на масив 16-бітних чисел, деякі з яких представляють символи, а деякі - половину сурогатної пари. Наприклад, str.lengthне повідомляє вам кількість символів у рядку, оскільки деякі символи займають більше місця, ніж інші; str.lengthповідомляє вам кількість 16-бітних чисел.
Теодор

289

Як hippietrail передбачає , відповідь Meder в може порушити сурогатні пари і перекручують «символи.» Наприклад:

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

Я пропоную використовувати одну з наступних функцій ES2015 для правильної обробки цих послідовностей символів.

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

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

Array.from

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

RegExp uпрапор

> '𝟘𝟙𝟚𝟛'.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]))/);
[ '𝟘', '𝟙', '𝟚', '𝟛' ]

Зауважте, що Babel намагається правильно поводитися з неперевершеними сурогатами. Однак, схоже, це не працює для неперевершених низьких сурогатів.

Перевірте все у своєму браузері:


Як ви сформували цих персонажів? Схоже, кожен символ має 4 байти.
user420667

2
@ user420667 символи є з додаткової площини символів (в таблиці unicode) з "великими" кодовими точками, тому вони не вписуються в 16 байт. Кодування utf-16, що використовується в JavaScript, представляє ці символи як сурогатні пари (спеціальні символи, які використовуються лише як пари для формування інших символів з додаткових площин). Тільки символи головної площини чарах представлені 16 байтами. Спеціальні символи пари сурогатних пар також виходять із площини головного персонажа, якщо він робить сенс.
Ольга

1
Виконання різних методик , розповсюдження виду нагадує чемпіон (хром 58).
Адріан

4
Зауважте, що це рішення розбиває деякі емоджи, такі як 🏳️‍🌈, і розбиває комбінацію діакритики з символів. Якщо ви хочете розділити на клафери графеми замість символів, перегляньте сторінку stackoverflow.com/a/45238376 .
користувач202729

3
Зауважте, що хоч і не розривати сурогатних пар - це чудово, але це не загальне рішення для збереження "символів" (а точніше - графем ) разом. Графема може складатися з декількох точок коду; наприклад, назва мови Devanagari - "देवनागरी", яка носієм мови читається як п’ять графем, але для отримання потрібно вісім кодових балів ...
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 ).


Демо

Спробуйте перед покупкою


1
Якщо ви використовуєте оператор розповсюдження в поєднанні з компілятором до ES5, це не працює в IE. Враховуйте це. Мені знадобилося кілька годин, щоб зрозуміти, в чому проблема.
Стеф ван ден Берг


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'


4
-1: це не так. Спробуйте:alert("Hello world!" == ['H','e','l','l','o',' ','w','o','r','l','d'])
Р. Мартіньо Фернандес

4
Вибачте. Я думаю, що я мав на увазі сказати: "Ви можете отримати доступ до окремих символів за допомогою посилання на індекс, як це, не створюючи масив символів".
dansimau

3
Не можна надійно перехрестити браузер, який ви не можете. Це функція ECMAScript Fifth Edition.
bobince

8
Крос-браузерна версія є mystring.charAt(index).
psmay

1
+1 для - charAt()хоча я вважаю за краще використовувати варіант масиву-ish. Дарн IE.
Zenexer

4

Є (принаймні) три різні речі, які ви можете уявити як "персонаж", і, отже, три різні категорії підходу, які ви можете використовувати.

Розщеплення на кодові одиниці UTF-16

Рядки JavaScript спочатку були винайдені як послідовності кодових одиниць UTF-16, ще в той момент історії, коли між кодовими блоками UTF-16 та кодовими кодами Unicode існував взаємозв'язок "один на один". .lengthВластивість рядки вимірює довжину в UTF-16 одиниць коди, і коли ви робите someString[i]ви отримуєте I - й UTF-16 код одиниці someString.

Отже, ви можете отримати масив кодових одиниць UTF-16 з рядка, використовуючи C-стиль for-loop із змінною індексу ...

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, це розділить їх на окремі кодові одиниці, що може не бути тим, що вам потрібно. Наприклад, рядок '𝟘𝟙𝟚𝟛'складається з чотирьох точок коду унікоду (кодові точки від 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! Це можливо, оскільки 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внизу складається з великої літери А з гострим акцентом, за якою йде прапор Сполученого Королівства, а за ним чорна жінка.)

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("")найшвидший варіант
Люкс

1
Також, .split("")здається, сильно оптимізований Firefox. Незважаючи на те, що цикл має схожі показники в хромірованому режимі, а розбиття 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(''));

-1

Як щодо цього?

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

@KyleMit це здається швидше, ніж для i loop + push jsperf.com/string-to-character-array/3
msand

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.