用空格分割字符串,保留带引号的段,允许转义引号

IT技术 javascript regex
2021-03-08 09:37:44

我目前有这个正则表达式可以按所有空格分割字符串,除非它在带引号的段中:

keywords = 'pop rock "hard rock"';
keywords = keywords.match(/\w+|"[^"]+"/g);
console.log(keywords); // [pop, rock, "hard rock"]

但是,我也希望可以在关键字中使用引号,如下所示:

keywords = 'pop rock "hard rock" "\"dream\" pop"';

这应该返回

[pop, rock, "hard rock", "\"dream\" pop"]

实现这一目标的最简单方法是什么?

4个回答

您可以将正则表达式更改为:

keywords = keywords.match(/\w+|"(?:\\"|[^"])+"/g);

而不是[^"]+你有(?:\\"|[^"])+which allowed\"或其他字符,但不是未转义的引号。

一个重要的注意事项是,如果您希望字符串包含文字斜杠,它应该是:

keywords = 'pop rock "hard rock" "\\"dream\\" pop"'; //note the escaped slashes.

此外,\w+之间有轻微的不一致[^"]+- 例如,它将匹配单词"ab*d", 但不匹配ab*d(没有引号)。考虑[^"\s]+改为使用,这将匹配非空格。

考虑一下:在字符串中"\\" "foo"(为了清楚起见,只有两个反斜杠),第一个"将与"正则表达式开头的文字匹配然后[^"]将匹配第一个\。然后剩余的\"将被匹配\\"(因为它在交替中排在第一位)。然后[^"]将匹配空格,并且"(在正则表达式的末尾)将匹配 的开头引号"foo",从而破坏解析。
2021-04-18 09:37:44
我建议您使用\\.而不是\\"因为反斜杠也可以转义,并且您不想错过"foo\\\\".
2021-04-27 09:37:44
它就像它应该的那样工作。"(?:\\"|[^"])+ 这应该是不言自明的" < 不是真的;-),我以前从未在正则表达式中使用过它,一位同事不得不向我解释。“考虑使用 [^”\s]+ 代替” < 这是我已经调整的内容。感谢您的帮助!
2021-05-01 09:37:44
@Kobi 公平点。对于它所关注的人,我已经(?<!\\)(?:\\\\)*在正则表达式之前。也就是说,前面没有反斜杠,后面必须有偶数个反斜杠(即转义的反斜杠)。换句话说,开头引号前面必须有 0, 2, 4, 6, ... 反斜杠,否则(即 1, 3, ... 反斜杠)我们不会认为它是开头引号。
2021-05-09 09:37:44
@Tim - 起初是个有趣的想法,但我不确定是否有必要 - 不会[^"]处理这些情况吗?我错过了什么吗?
2021-05-11 09:37:44

ES6 解决方案支持:

  • 除内引号外,按空格分割
  • 删除引号但不是用于反斜杠转义引号
  • 转义报价成为报价
  • 可以在任何地方放置引号

代码:

keywords.match(/\\?.|^$/g).reduce((p, c) => {
        if(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

输出:

[ 'pop', 'rock', 'hard rock', '"dream" pop' ]
您的代码真的很难阅读,但它有效并且正是我正在寻找的。
2021-04-29 09:37:44
这行得通,TRIMS QUOTES 这正是我所需要的;同意虽然很难阅读
2021-04-30 09:37:44

如果 Kobi 的答案适用于示例字符串,那么当Tim Pietzcker 在评论中注意到的引号之间有多个连续的转义字符(反斜杠)时,它不会为了处理这些情况,模式可以这样写(对于 match 方法)

(?=\S)[^"\s]*(?:"[^\\"]*(?:\\[\s\S][^\\"]*)*"[^"\s]*)*

演示

where(?=\S)确保在当前位置至少有一个非空白字符,因为以下描述所有允许的子字符串(包括引号之间的空格)是完全可选的。

细节:

(?=\S)   # followed by a non-whitespace
[^"\s]*  #"# zero or more characters that aren't a quote or a whitespace
(?: # when a quoted substring occurs:
    "       #"# opening quote
    [^\\"]* #"# zero or more characters that aren't a quote or a backslash
    (?: # when a backslash is encountered:
        \\ [\s\S] # an escaped character (including a quote or a backslash)
        [^\\"]* #"#
    )*
    "         #"# closing quote
    [^"\s]*   #"#
)*
这很好用!但是如果我想让它也适用于单引号呢?
2021-04-17 09:37:44
正如我相信 OP 所要求的那样,这有效并保留了报价。
2021-05-02 09:37:44
@Timo:我添加了图案细节。
2021-05-05 09:37:44
能不能用通俗的英文补充一下各部分的意思?
2021-05-13 09:37:44

我想指出我和你有相同的正则表达式,

/\w+|"[^"]+"/g

但它不适用于空引号字符串,例如:

"" "hello" "" "hi"

所以我不得不通过 * 更改 + 量词。这给了我:

str.match(/\w+|"[^"]*"/g);

这很好。

(例如:https : //regex101.com/r/wm5puK/1