在空格和引号上拆分字符串,保持引用的子字符串不变

时间:2018-03-08 18:00:22

标签: javascript regex

我需要一种方法来在空格上分割字符串,但保持引用的子字符串不变。

例如:

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 }}

1 个答案:

答案 0 :(得分:1)

有一个类似“分裂空格和引号”的批次“Q& As在SO上,大多数都带有正则表达式解决方案。事实上,您的代码至少可以在one of them中找到(感谢for thattry-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);