JavaScript按空格拆分字符串但不包括引号内的空格

8
目标是在空格处拆分字符串,但不会将在引号中的文本数据拆分或与相邻文本分离。
输入实际上是一个包含值对列表的字符串。如果值包含空格,则用引号括起来。我需要一个函数,按照以下示例返回一个值对元素数组:
示例输入:
'a:0 b:1 moo:"foo bar" c:2'
预期结果:
a:0,b:1,moo:foo bar,c:2 (长度为4的数组)
我已经检查了大量其他问题,但没有一个(我找到的)似乎能够处理我的问题。大多数似乎在引号内的空格处拆分,或者将“moo:”和“foo bar”拆分成单独的部分。
任何帮助都将不胜感激,Craig

4
可能是Regex to pick commas outside of quotes的重复问题。 - Avinash Raj
只需将以上链接中的逗号替换为空格。 - Avinash Raj
2
上面的链接并没有达到预期的效果,它执行的是替换而不是分割。 - Crog
有很多解决方案,但我已经接受了Moob的解决方案,因为它完美地适应了问题场景,并通过消除对值周围引号的必要性来改善了情况,从而增强了系统。 - Crog
你也可以使用相同的正则表达式来进行分割。 - Avinash Raj
3个回答

16

您可以使用此正则表达式进行拆分:

var s = 'a:0 b:1 moo:"foo bar" c:2';

var m = s.split(/ +(?=(?:(?:[^"]*"){2})*[^"]*$)/g);
//=> [a:0, b:1, moo:"foo bar", c:2]

正则表达式演示

它仅在引号外使用正向预查将空格拆分,以确保一个空格后面有偶数个引号。


2
+1,这太棒了,但我真的希望能有更详细的解释 :) - epoch
感谢@epoch:这个假设引号是平衡和未转义的。如果一个空格在引号外面,那么直到行尾跟随空格的引号数量总是0或偶数。这正是这个前瞻(?=(?:(?:[^"]*"){2})*[^"]*$)所做的。 - anubhava
哇,太棒了。我找到的其他正则表达式都没有像你的答案anubhava那样有效。希望我们能更多地了解它的工作原理。另外,是否可以按照示例删除引号?不过这并不是什么大问题。 - Crog
但是您仍然选择接受另一个答案,该答案并没有完全按照您在问题中所要求的执行,并且在最终结果中也返回了 moo:"foo bar" - anubhava
1
警告,/ +(?=(?:(?:[^"]*"){2})*[^"]*$)/是一个非常慢的模式,如果您有长字符串,请考虑使用不同的表达式,以避免经历减速(例如在这里描述)。 - Wiktor Stribiżew
显示剩余2条评论

4
你可以稍微有所不同地处理它,使用正则表达式来分割空格后跟随单词字符和冒号的位置(而不是不在引用部分中的空格)。
var str = 'a:0 b:1 moo:"foo bar" c:2',
    arr = str.split(/ +(?=[\w]+\:)/g);
/* [a:0, b:1, moo:"foo bar", c:2] */

演示 jsFiddle

这个正则表达式在做什么?
它寻找空格字符的字面匹配,然后使用正向先行断言来断言下一部分可以匹配:
[\w]+ = 匹配一个或多个单词字符[a-zA-Z0-9_]。
\: = 匹配一个冒号字符:(反斜杠转义)。
g = 全局修饰符——不要在第一次匹配时返回。

演示 Regex101(带解释)


这比anubhavas的正则表达式要短得多。我对它们的了解不够,但似乎可以完成同样的工作,其他人已经赞同了另一个解决方案,但现在两者都没有从结果中省略引号,但这并不重要。 - Crog
再读一遍,我看到了你的解决方案的优雅之处。它完美地契合了问题描述。实际上,这使得在值文本中使用引号变得不再必要。 - Crog
我已经理解了,我能否在代码中将空格、' '和':'变成一个变量?我不确定如何将其添加到这种类型的正则表达式中。 - Crog

2

为什么必须使用正则表达式呢?

var str = 'a:0 b:1 moo:"foo bar" c:2';

var parts = [];
var currentPart = "";
var isInQuotes= false;

for (var i = 0; i < str.length, i++) {
  var char = str.charAt(i);
  if (char === " " && !isInQuotes) {
    parts.push(currentPart);
    currentPart = "";
  } else {
    currentPart += char;
  }
  if (char === '"') {
    isInQuotes = !isInQuotes;
  }
}

if (currentPart) parts.push(currentPart);

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