Разделить строку пробелами, сохраняя процитированные сегменты, позволяя избежать кавычек
В настоящее время я использую это регулярное выражение для разделения строк на все пробелы, если только это не указано в сегменте:
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"]
Какой самый простой способ достичь этого?
Ответы
Ответ 1
Вы можете изменить свое регулярное выражение на:
keywords = keywords.match(/\w+|"(?:\\"|[^"])+"/g);
Вместо [^"]+
у вас есть (?:\\"|[^"])+
, который должен быть понятным - разрешить \"
или другой символ, но не неэкономную цитату.
Важное замечание состоит в том, что если вы хотите, чтобы строка содержала литеральную косую черту, она должна быть:
keywords = 'pop rock "hard rock" "\\"dream\\" pop"'; //note the escaped slashes.
Кроме того, существует небольшая несогласованность между \w+
и [^"]+
- например, она будет соответствовать слову "ab*d"
, но не ab*d
(без кавычек). Вместо этого используйте [^"\s]+
, который будет соответствовать не-пробелам.
Ответ 2
Решение 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' ]
Ответ 3
Если ответ Kobi хорошо работает для строки примера, это происходит не тогда, когда в кавычках более нескольких последовательных escape-символов (обратных косых черт), когда Tim Pietzcker заметил это в комментариях. Чтобы обрабатывать эти случаи, шаблон можно записать следующим образом (для метода сопоставления):
(?=\S)[^"\s]*(?:"[^\\"]*(?:\\[\s\S][^\\"]*)*"[^"\s]*)*
демо
Где (?=\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]* #"#
)*
Ответ 4
Я хотел бы указать, что у меня было такое же регулярное выражение, что и вы,
/\w+|"[^"]+"/g
но он не работал с пустой цитируемой строкой, например:
"" "hello" "" "hi"
поэтому мне пришлось изменить квант + на *.
это дало мне:
str.match(/\w+|"[^"]*"/g);
Это нормально.
(например: https://regex101.com/r/wm5puK/1)