将字符串分割成数组而不删除分隔符?

25
我有一个字符串,例如
 "asdf a  b c2 "

我想要将其拆分为以下数组:

["asdf", " ", "a", " ", " ", "b", " ", "c2", " "]

使用 string.split(" ") 会移除空格,导致结果变为:

["asdf", "a", "", "b", "c2"]

我考虑插入额外的分隔符,例如:

string.replace(/ /g, "| |").replace(/||/g, "|").split("|");

但这会产生一个意想不到的结果。

5个回答

23

不要想着拆分,而应该想着提取包含定界符或者连续字符的字符串,这些字符不是定界符:

'asdf a  b c2 '.match(/\S+|\s/g)
// result: ["asdf", " ", "a", " ", " ", "b", " ", "c2", " "]
'asdf a  b. . c2% * '.match(/\S+|\s/g)
// result: ["asdf", " ", "a", " ", " ", "b.", " ", ".", " ", "c2%", " ", "*", " "]

更具莎士比亚风格的定义可将比赛描述为:
'asdf a  b c2 '.match(/ |[^ ]+/g)

要用还是不用,这是一个问题。


@Jack 我之前没用过,但好像可以用!显然,我需要学习正则表达式.. \S+ 是什么意思? - gandalf3
2
@gandalf3зҡ„\SжҳҜ\sзҡ„зӣёеҸҚпјҢе®ғд№ҹеҸҜд»ҘеҶҷжҲҗ[^\s]гҖӮ - Ja͢ck
+1 但请注意:将其包装在非捕获组中((?: ))是不必要的。'asdf a b c2 '.match(/\S+|\s/g) 将是相同的。 - p.s.w.g

10

使用正向预查:

"asdf a  b c2 ".split(/(?= )/)
// => ["asdf", " a", " ", " b", " c2", " "]

编辑后的说明: 正如我在评论中所说,缺少反向查找使得这变得有些棘手。如果所有单词只包含字母,则可以使用\b单词边界匹配器来伪造反向查找:

"asdf a  b c2 ".split(/(?= )|\b/)
// => ["asdf", " ", "a", " ", " ", "b", " ", "c2", " "]

但是一旦加上了一些标点符号,它就无法正常工作,因为它不仅会在空格处断开:

"asdf-eif.b".split(/(?= )|\b/)
// => ["asdf", "-", "eif", ".", "b"]

如果您有不想分割的非字母字符,那么我还将建议一种后处理方法。
后续编辑:这基于JamesA的原始想法,但经过改进以不使用jQuery,并正确拆分:
function chop(str) {
  var result = [];
  var pastFirst = false;
  str.split(' ').forEach(function(x) {
    if (pastFirst) result.push(' ');
    if (x.length) result.push(x);
    pastFirst = true;
  });
  return result;
}
chop("asdf a  b c2 ")
// => ["asdf", " ", "a", " ", " ", "b", " ", "c2", " "]

这对我在问题中所写的内容非常有效,但我刚意识到我在示例中犯了一个错误...请查看我编辑后的问题。 - gandalf3
@gandalf3 你希望它们不是字符串吗? - Henrik Andersson
@limelights 我希望每个空格都在一个单独的元素中。一个元素中不应该有空格+其他任何内容。 - gandalf3
1
@limelights:最初的分割是在每个空格之前;现在是在每个空格之前和之后。不幸的是,JavaScript没有向后查找,所以这有点困难... - Amadan
谢谢!这个很好用,但我接受了杰克的答案,因为它更短(尽管该解决方案会在任何空格字符上拆分,而不仅仅是空格。但对于我的情况来说,这没问题)。如果可以的话,我会接受两个.. (顺便加一) - gandalf3

8

我很惊讶还没有人提到这个,但为了完整起见,在此发布。如果您的表达式中有捕获组,则.split将把捕获的子字符串作为结果数组中的单独条目包含:

"asdf a  b c2 ".split(/( )/)  // or /(\s)/
// ["asdf", " ", "a", " ", "", " ", "b", " ", "c2", " ", ""]

注意,这并不完全与您指定的期望输出相同,因为它在两个相邻空格之间和最后一个空格之后包括一个空字符串。
如果必要,您可以像这样从结果数组中过滤出所有空字符串:
"asdf a  b c2 ".split(/( )/).filter(String)
// ["asdf", " ", "a", " ", " ", "b", " ", "c2", " "]

然而,如果这正是你想要的,我可能会建议您选择@Jack的解决方案。


抱歉..最后的空字符串是打错了。我已经编辑了我的问题。 - gandalf3
@gandalf3 好的,我已经提供了另一种解决方案,可以在这种情况下为您获得所需的结果。 - p.s.w.g

1
尝试使用 clean-split
const cleanSplit = require("clean-split");

cleanSplit("a-b-c", "-");
//=> ["a", "-", "b", "-", "c"]

cleanSplit("a-b-c", "-", { anchor: "before" });
//=> ["a-", "b-", "c"]

cleanSplit("a-b-c", "-", { anchor: "after" });
//=> ["a", "-b", "-c"]

在底层,它使用了以下逻辑:

在您的情况下,您可以像这样做:

const cleanSplit = require("clean-split");

cleanSplit("asdf a  b c2 ", " ");
//=> ["asdf", " ", "a", " ", " ", "b", " ", "c2", " "]

0
你可以使用一点jQuery。
var toSplit = "asdf a  b c2 ".split(" ");
$.each(toSplit, 
    function(index, value) { 
        if (toSplit[index] == '') { toSplit[index] = ' '} 
    }
);

这将创建所需的输出,而其他元素上的前导空格则不会出现。

5
在更新的环境中不需要jQuery - jQuery.each是一个贫民版的[].foreach - Amadan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接