Разбить строку по пробелу, сохранив сегменты в кавычках, позволяя экранировать кавычки - PullRequest
24 голосов
/ 27 октября 2010

В настоящее время у меня есть это регулярное выражение для разделения строк по всем пробелам, если только оно не находится в сегменте в кавычках:

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 ]

28 голосов
/ 27 октября 2010

Вы можете изменить свое регулярное выражение на:

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

Вместо [^"]+ вы получите (?:\\"|[^"])+, который допускает \" или другой символ, но не цитату без экранирования.1008 * Одно важное замечание: если вы хотите, чтобы строка включала буквальный слеш, она должна быть:

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

Кроме того, между \w+ и [^"]+ имеется небольшое несоответствие, напримербудет соответствовать слову "ab*d", но не ab*d (без кавычек).Попробуйте вместо этого использовать [^"\s]+, который будет соответствовать не пробелам.

4 голосов
/ 26 октября 2017

Решение 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' ]
1 голос
/ 19 октября 2016

Если ответ Коби хорошо работает для примера строки, он не работает, если между кавычками более одного последовательного escape-символа (обратная косая черта) , как заметил Тим Пиццкер в комментариях.Для обработки этих случаев шаблон можно записать так: (для метода сопоставления) :

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

demo

Где (?=\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]*   #"#
)*
0 голосов
/ 05 января 2017

Я хотел бы отметить, что у меня было то же регулярное выражение, что и у вас,

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

, но оно не работало с пустой строкой в ​​кавычках, такой как:

"" "hello" "" "hi"

, поэтому мне пришлосьизмените + квантификатор на *.это дало мне:

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

Что хорошо.

(например: https://regex101.com/r/wm5puK/1)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...