如何在JavaScript中将字符串获取到字符数组?


369

如何在JavaScript中将字符串转换为字符数组?

我在想得到像"Hello world!"数组这样的字符串
['H','e','l','l','o',' ','w','o','r','l','d','!']

Answers:


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位数字的数量。
Theodore Norvell

289

正如hippietrail所建议的那样merder的答案可能会破坏代理对并误解“字符”。例如:

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

我建议使用以下ES2015功能之一来正确处理这些字符序列。

传播语法(此处通过insertusername 回答

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

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 '16

2
@ user420667字符来自带有“大”代码点的附加字符平面(在unicode表中),因此它们不适合16个字节。javascript中使用的utf-16编码将这些字符显示为代理对(特殊字符仅用作对,以形成其他平面中的其他字符)。仅主字符平面的字符以16个字节表示。Surrugate对特殊字符也来自主字符平面(如果有意义)。
奥尔加

1
不同技术的表现,传播op看起来像冠军(chrome 58)。
阿德里安

4
请注意,此解决方案拆分了一些表情符号(例如)🏳️‍🌈,并拆分了从字符中结合变音符号的符号。如果要拆分成字素簇而不是字符,请参阅stackoverflow.com/a/45238376
user202729

3
注意,尽管未分裂开代理对是很大的,它不是用于保持“字符”(或更准确地,通用溶液字形)在一起。字素可以由多个代码点组成。例如,梵文语言的名字是“देवनागरी”,母语的人将其读为5个字素,但需要8个代码点才能产生...
TJ Crowder

71

spread语法

您可以使用传播语法,这是ECMAScript 2015(ES6)标准中引入的Array Initializer :

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”(例如,在PHPRuby中或被称为“ scatter”(例如,在Python中)。


演示版

购买前尝试


1
如果将散布运算符与ES5编译器结合使用,则在IE中将无法使用。考虑到这一点。我花了几个小时才弄清楚问题出在哪里。
Stef van den Berg,

13

您也可以使用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', '!' ]

不一定是对还是错,只是另一种选择。

在MDN站点上很好地描述了Object.assign。


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'])
R. Martinho Fernandes

4
抱歉。我想我想说的是:“您可以像这样通过索引引用访问单个字符,而无需创建字符数组”。
dansimau 2010年

3
没有可靠的跨浏览器,您无法做到。这是ECMAScript第五版功能。
bobince 2010年

8
跨浏览器版本为mystring.charAt(index)
psmay

1
+ charAt()1-尽管我更喜欢使用array-ish变体。达恩IE。
Zenexer 2014年

4

您可能将(至少)三种不同的事物视为“角色”,因此,可能要使用三种不同的方法类别。

拆分为UTF-16代码单元

JavaScript字符串最初是作为UTF-16代码单元的序列而发明的,可追溯到历史上的某个时刻,当时UTF-16代码单元与Unicode代码点之间存在一对一的关系。.length字符串的属性以UTF-16代码单位度量其长度,并且在someString[i]获取字符串的第i个UTF-16代码单位时someString

因此,通过使用带有索引变量的C样式for循环,您可以从字符串中获取UTF-16代码单元的数组。

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中,每个unicode代码点均由两个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);

然而,Unicode码点是不是也可能会被认为是一个“性格”最大可能的事情要么。可以合理地视为单个“字符”但由多个代码点组成的事物的一些示例包括:

  • 重音字符,如果重音带有组合代码点
  • 标志
  • 一些表情符号

我们可以从下面看到,如果尝试通过上述迭代机制将具有此类字符的字符串转换为数组,则这些字符最终会分解为结果数组。(如果系统上未显示任何字符,则yourString下面的字符由带有重音符号的大写字母A组成,其后是英国国旗,然后是黑人女性。)

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

如果我们要保持每一种在我们的最后一个数组中的单个项目,那么我们需要的数组字形,而不是代码点。

分裂成字素

JavaScript没有对此的内置支持-至少现在还没有。因此,我们需要一个能够理解并实现Unicode规则的库,以了解哪些代码点组合构成了字素。幸运的是,存在一个:Orling的字素分解器。您需要使用npm进行安装,或者,如果您不使用npm,请下载index.js文件并为其<script>添加标签。对于此演示,我将从jsDelivr加载它。

字形分离器给了我们一个GraphemeSplitter班有三种方法:splitGraphemesiterateGraphemes,和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
尽管此方法比声明式命令更重要,但它是此线程中性能最高的,值得更多的关注。一个限制对位置的字符串检索一个字符是与过去的人物打交道时,基本多文种计划中的Unicode,如表情符号。 "😃".charAt(0)将返回一个无法使用的角色
KyleMit

2
@KyleMit这似乎仅适用于简短输入。使用更长的输入将.split("")再次成为最快的选择
勒克斯

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

-1

这个怎么样?

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

@KyleMit这似乎比我更快的循环推+ jsperf.com/string-to-character-array/3
msand

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.