我需要一种方法来在空格上分割字符串,但保持引用的子字符串不变。
例如:
Input:
str = 'this "is a"test string'
Output:
[this, is a, test, string]
当我使用时:
str.match(/\\?.|^$/g).reduce((p, c) => {
if(c === '"' || c === "'"){
p.quote ^= 1;
}else if(!p.quote && c === ' '){
p.a.push('');
}else{
p.a[p.a.length-1] += c.replace(/\\(.)/,"$1");
}
return p;
}, {a: ['']}).a
它保持引用的子串完整,并根据需要拆分空格。
但是,它不会在提供的示例中正确地拆分术语,其中引用的子字符串后面紧跟一个字母。相反,我得到的结果是:
[this, is atest, string]
修改
我认为这个问题与其他类似的问题不同,因为在结束引用之后没有空格时,它们都没有排除引号和正确地拆分条件,如下例所示:{{1 }}
答案 0 :(得分:1)
有一个类似“分裂空格和引号”的批次“Q& As在SO上,大多数都带有正则表达式解决方案。事实上,您的代码至少可以在one of them中找到(感谢for that,try-catch-finally)。
虽然其中一些解决方案不包括引号,但如果在结束引号后面没有空格分隔符,则只有一个我能找到的解决方案,并且它们都不会排除引号并允许缺少空格。
这也不仅仅是适应任何正则表达式的简单问题。如果您确实更改了正则表达式以使用捕获组,则不再可能使用简单的match
方法。 (通常的技巧是在循环中使用exec
。)如果不使用捕获组,则需要在之后执行字符串操作以删除引号。
最新的解决方案是对map
的数组结果使用match
。
使用slice
字符串操作方法:
var str = 'this "is a"test string';
var result = str.match(/"[^"]*"|\S+/g).map(m => m.slice(0, 1) === '"'? m.slice(1, -1): m);
console.log(result);
使用捕获组:
var str = 'this "is a"test string';
var regex = /"([^"]*)"|(\S+)/g;
var result = (str.match(regex) || []).map(m => m.replace(regex, '$1$2'));
console.log(result);
捕获组解决方案更为通用,例如,可以轻松扩展以允许不同的引号。
请注意,上述两种解决方案中使用的正则表达式都非常简单,仅适用于双引号,并且子字符串中没有转义引号。 (不过,它适用于嵌套的单引号和撇号。)
正则表达式的解释:
"[^"]*"
→"
后跟任意数量的非"
个字符,后跟"
|
→或
\S+
→任何连续的非空白字符序列
请注意,这两个组的顺序至关重要。如果首先使用\S+
,它将与开头的引号以及后面的第一个单词匹配。
对于您尝试使用的状态机代码,它是非常严格的,仅适用于精确术语之间的一个空格,并且如果在任何地方使用任何撇号则会中断(因为它也允许要单引号的子字符串。)
通过在检测到结束引号时按空字符串,可以 修复以适用于您的特定示例。要在结束引号后允许单个空格,在推送新字符串之前需要检查现有的空字符串:
var str = 'this "is a"test string';
var result = str.match(/\\?.|^$/g).reduce((p, c) => {
if(c === '"' || c === "'"){
if(!(p.quote ^= 1)){p.a.push('');} // <- modified
}else if(!p.quote && c === ' ' && p.a[p.a.length-1] !== ''){ // <- modified
p.a.push('');
}else{
p.a[p.a.length-1] += c.replace(/\\(.)/,"$1");
}
return p;
}, {a: ['']}).a
console.log(result);