我想获取一个像
"Hello world!"
这样的字符串,并将其转换为数组['H','e','l','l','o','','w','o','r','l','d','!']
"Hello world!"
这样的字符串,并将其转换为数组['H','e','l','l','o','','w','o','r','l','d','!']
注意:这不符合Unicode标准。
"IU".split('')
的结果是一个由4个字符组成的数组["I", "�", "�", "u"]
,可能会导致严重的错误。请查看下面的答案以获得安全可靠的替代方法。
只需用空字符串进行分割即可。
var output = "Hello world!".split('');
console.log(output);
正如hippietrail建议的那样, meder的回答可以打破代理对并误解“字符”。例如:
// DO NOT USE THIS!
const a = ''.split('');
console.log(a);
// Output: ["�","�","�","�","�","�","�","�"]
我建议使用以下ES2015功能来正确处理这些字符序列。
const a = [...''];
console.log(a);
const a = Array.from('');
console.log(a);
u
标志const a = ''.split(/(?=[\s\S])/u);
console.log(a);
/(?=[\s\S])/u
代替/(?=.)/u
,因为.
不匹配换行符。如果您仍处于ES5.1时代(或者您的浏览器无法正确处理此正则表达式-例如Edge),则可以使用以下替代方案(由Babel转译)。请注意,Babel还尝试正确处理未匹配的代理项。但是,这似乎对未匹配的低代理项无效。
const a = ''.split(/(?=(?:[\0-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]))/);
console.log(a);
for ... of ...
循环结构const s = '';
const a = [];
for (const s2 of s) {
a.push(s2);
}
console.log(a);
️
)拆分开,并将附加的重音符号从字符中拆分出来。如果您想要将其拆分为字形簇而不是字符,请参见https://dev59.com/w2w15IYBdhLWcg3wo9Rx#45238376。 - user202729spread
语法
您可以使用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"}
浏览器支持
进一步阅读
spread
也被称为"splat
"(例如在PHP或Ruby中),或者作为"scatter
"(例如在Python中)。
演示
在编程中,我们可以把“字符”看做至少三个不同的事物,并因此采用三个不同的方法来处理。
JavaScript字符串最初是作为一系列UTF-16码单元发明的,在当时UTF-16码单元与Unicode码点之间存在一对一的关系。字符串的.length
属性测量它在UTF-16码单元中的长度,当你使用someString[i]
时,可以得到someString
的第i个UTF-16码单元。
因此,您可以使用类似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中,每个代码点由两个UTF-16代码单元组成。如果我们使用上述方法拆分该字符串,我们将得到一个由八个代码单元组成的数组:
const yourString = '';
console.log('First code unit:', yourString[0]);
const charArray = yourString.split('');
console.log('charArray:', charArray);
也许我们想将字符串分割为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
来缩短代码,它会隐式地迭代传递给它的iterable对象:
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的grapheme-splitter。您可以使用npm安装它,或者如果您不使用npm,则下载index.js文件并使用<script>
标签提供服务。对于此演示,我将从jsDelivr加载它。
grapheme-splitter为我们提供了一个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>
现在我们得到了一个由三个字形组成的数组,这很可能是你想要的。
Array.from
。
var m = "Hello world!";
console.log(Array.from(m))
这个方法已经在ES6中被引入。
Array.from()
静态方法可以从可迭代对象(iterable)或类数组对象(array-like)中创建一个新的浅拷贝的Array
实例。
var output = Object.assign([], "Hello, world!");
console.log(output);
// [ 'H', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '!' ]
这并不一定对或错,只是另一个选择。
Array.from("Hello, world")
。 - T.J. Crowder[..."Hello, world"]
。 - chharveyObject.assign([], "")
是 [ "\ud83e", "\udd8a" ]
。这显然是错误的。 - Sebastian SimonArray.from
等是正确的解决方案,而Object.assign
等则是不正确的解决方案。提供仅在有限情况下勉强工作的解决方案的情感对软件行业是有害的。 - Sebastian Simon它已经是:
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'
alert("Hello world!" == ['H','e','l','l','o',' ','w','o','r','l','d'])
- R. Martinho Fernandesmystring.charAt(index)
。 - psmaycharAt()
函数我会给一个赞。该死的 IE。 - Zenexer在JavaScript中,您可以通过以下四种方式将字符串转换为字符数组:
const string = 'word';
// Option 1
string.split(''); // ['w', 'o', 'r', 'd']
// Option 2
[...string]; // ['w', 'o', 'r', 'd']
// Option 3
Array.from(string); // ['w', 'o', 'r', 'd']
// Option 4
Object.assign([], string); // ['w', 'o', 'r', 'd']
"".split("")
和Object.assign([], "")
分别为[ "\ud83e", "\udd8a" ]
(由于字符串是UTF-16编码的,因此必要时按其代理字节对进行索引); [ ..."" ]
和Array.from("")
是等效的,并且结果为[ "" ]
(由于这两种方法访问Symbol.iterator
属性,该属性具有Unicode感知能力)。 - Sebastian Simonarray = [...myString];
例子:
let myString = "Hello world!"
array = [...myString];
console.log(array);
// another example:
console.log([..."another splitted text"]);
正如Mark Amery在他的优秀回答中指出的那样,仅仅按代码点进行分割可能是不够的,尤其是对于特定的表情符号或组合字符(例如:ñ
由两个代码点n
和̃
组成,形成一个字形)。JavaScript有一个内置的字形分段器,可通过国际化API(Intl
)调用,名为Intl.Segmenter
。它可以用于按不同的粒度分段字符串,其中之一是字形(即字符串的用户感知字符):
const graphemeSplit = str => {
const segmenter = new Intl.Segmenter("en", {granularity: 'grapheme'});
const segitr = segmenter.segment(str);
return Array.from(segitr, ({segment}) => segment);
}
// See browser console for output
console.log("Composite pair test", graphemeSplit("foo bar mañana mañana"));
console.log("Variation selector test", graphemeSplit("❤️"));
console.log("ZWJ Test:", graphemeSplit("❤️"));
console.log("Multiple Code Points:", graphemeSplit("देवनागरी"));
ñ
)的不错选项。然而,它无法适用于由多个代码点组成的所有类型字符(例如表情符号),但如果字符串由可组合的代码点组成,则是一个很好的选择。 - Nick ParsonsIntl.Segmenter
在Firefox中还没有任何支持,因此,除非我能找到一个好的polyfill,否则我不想在公共面向网页上使用它。阅读完这个答案后,我仍然对两件事情感到不确定:首先,如果想在公共网络上使用它,是否存在一个好的polyfill,其次,为什么Intl.Segmenter
需要一个语言环境参数,它有什么影响?。 - Mark Amery@formatjs Intl.Segmenter
polyfill:https://github.com/formatjs/formatjs/tree/main/packages/intl-segmenter 也可以参考 https://dev59.com/XHNA5IYBdhLWcg3wSrqa#76777557 - mrienstra
"".split('')
的结果为["�", "�"]
。 - hippietrail"randomstring".length;
//12"randomstring"[2];
//"n" - Luigi van der Palstr.length
并不能告诉你字符串中字符的数量,因为某些字符需要更多的空间;str.length
告诉你的是16位数字的数量。 - Theodore Norvell