Мне нужно указать точные фразы (заключенные в кавычки) в списке терминов, разделенных пробелами. Таким образом, разделения соответствующей строки пробелом уже недостаточно.
Пример:
input : 'foo bar "lorem ipsum" baz'
output: ['foo', 'bar', 'lorem ipsum', 'baz']
Интересно, можно ли этого достичь с помощью одного RegEx, а не выполнять сложный синтаксический анализ или операции разделения и повторного соединения.
Любая помощь будет принята с благодарностью!



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


'foo bar "lorem ipsum" baz'.match(/"[^"]*"|\w+/g);
ограничивающие кавычки включены, хотя
Подойдет простое регулярное выражение, но оставьте кавычки. например
'foo bar "lorem ipsum" baz'.match(/("[^"]*")|([^\s"]+)/g)
output: ['foo', 'bar', '"lorem ipsum"', 'baz']
изменить: избит shyamsundar, извините за двойной ответ
как насчет,
output = /(".+?"|\w+)/g.exec(input)
затем выполните переход на вывод, чтобы потерять кавычки.
поочередно,
output = /"(.+?)"|(\w+)/g.exec(input)
затем выполните вывод pass n, чтобы потерять пустые захваты.
var str = 'foo bar "lorem ipsum" baz';
var results = str.match(/("[^"]+"|[^"\s]+)/g);
... возвращает массив, который вы ищете. Однако обратите внимание:
replace(/^"([^"]+)"$/,"").lorem и ipsum есть три пробела, они будут в результате. Вы можете исправить это, запустив replace(/\s+/," ") по результатам." нет закрывающего ipsum (т. Е. Неправильно цитируемой фразы), вы получите: ['foo', 'bar', 'lorem', 'ipsum', 'baz']Хорошо, только не найти цитату из scape, например: ['foo', 'bar', 'lorem \' ipsum ',' baz ']
отлично! это простой способ реализовать синтаксический анализатор поисковой системы для поиска фраз и отдельных слов ... очень признателен!
Спасибо за этот ответ. Я опубликовал свою реализацию парсера поисковой системы для фраз и отдельных слов в качестве другого ответа, где фразы обрабатываются как регулярные выражения.
Попробуй это:
var input = 'foo bar "lorem ipsum" baz';
var R = /(\w|\s)*\w(? = ")|\w+/g;
var output = input.match(R);
output is ["foo", "bar", "lorem ipsum", "baz"]
Обратите внимание, что lorem ipsum не заключен в двойные кавычки.
Хотя предполагается, что на входе есть двойные кавычки в нужном месте:
var input2 = 'foo bar lorem ipsum" baz'; var output2 = input2.match(R);
var input3 = 'foo bar "lorem ipsum baz'; var output3 = input3.match(R);
output2 is ["foo bar lorem ipsum", "baz"]
output3 is ["foo", "bar", "lorem", "ipsum", "baz"]
И не будет обрабатывать экранированные двойные кавычки (это проблема?):
var input4 = 'foo b\"ar bar\" \"bar "lorem ipsum" baz';
var output4 = input4.match(R);
output4 is ["foo b", "ar bar", "bar", "lorem ipsum", "baz"]
Большое спасибо за быстрые ответы!
Вот краткое изложение вариантов для потомков:
var input = 'foo bar "lorem ipsum" baz';
output = input.match(/("[^"]+"|[^"\s]+)/g);
output = input.match(/"[^"]*"|\w+/g);
output = input.match(/("[^"]*")|([^\s"]+)/g)
output = /(".+?"|\w+)/g.exec(input);
output = /"(.+?)"|(\w+)/g.exec(input);
Для протокола, вот мерзость, которую я придумал:
var input = 'foo bar "lorem ipsum" "dolor sit amet" baz';
var terms = input.split(" ");
var items = [];
var buffer = [];
for(var i = 0; i < terms.length; i++) {
if (terms[i].indexOf('"') != -1) { // outer phrase fragment -- N.B.: assumes quote is either first or last character
if (buffer.length === 0) { // beginning of phrase
//console.info("start:", terms[i]);
buffer.push(terms[i].substr(1));
} else { // end of phrase
//console.info("end:", terms[i]);
buffer.push(terms[i].substr(0, terms[i].length - 1));
items.push(buffer.join(" "));
buffer = [];
}
} else if (buffer.length != 0) { // inner phrase fragment
//console.info("cont'd:", terms[i]);
buffer.push(terms[i]);
} else { // individual term
//console.info("standalone:", terms[i]);
items.push(terms[i]);
}
//console.info(items, "\n", buffer);
}
items = items.concat(buffer);
//console.info(items);
Одно простое для понимания и общее решение. Работает со всеми разделителями и символами «присоединения». Также поддерживает «соединенные» слова, длина которых превышает два слова .... т. Е. Списки вроде
"hello my name is 'jon delaware smith fred' I have a 'long name'" ....
Немного похоже на ответ AC, но немного аккуратнее ...
function split(input, delimiter, joiner){
var output = [];
var joint = [];
input.split(delimiter).forEach(function(element){
if (joint.length > 0 && element.indexOf(joiner) === element.length - 1)
{
output.push(joint.join(delimiter) + delimiter + element);
joint = [];
}
if (joint.length > 0 || element.indexOf(joiner) === 0)
{
joint.push(element);
}
if (joint.length === 0 && element.indexOf(joiner) !== element.length - 1)
{
output.push(element);
joint = [];
}
});
return output;
}
Это может быть очень поздний ответ, но мне интересно ответить
([\w]+|\"[\w\s]+\")
http://regex101.com/r/dZ1vT6/72
Пример чистого javascript
'The rain in "SPAIN stays" mainly in the plain'.match(/[\w]+|\"[\w\s]+\"/g)
Выходы:
["The", "rain", "in", ""SPAIN stays"", "mainly", "in", "the", "plain"]
Это не поддерживает Юникод, например, не поддерживает арабские символы.
Решение ES6, поддерживающее:
Код:
input.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(/\(.)/,"");
}
return p;
}, {a: ['']}).a
Выход:
[ 'foo', 'bar', 'lorem ipsum', 'baz' ]
Продолжая принятый ответ, вот синтаксический анализатор поисковой системы, который,
Обработка фраз как регулярных выражений упрощает пользовательский интерфейс для моих целей.
const matchOrIncludes = (str, search, useMatch = true) => {
if (useMatch) {
let result = false
try {
result = str.match(search)
} catch (err) {
return false
}
return result
}
return str.includes(search)
}
const itemMatches = (item, searchString, fields) => {
const keywords = searchString.toString().replace(/\s\s+/g, ' ').trim().toLocaleLowerCase().match(/(-?"[^"]+"|[^"\s]+)/g) || []
for (let i = 0; i < keywords.length; i++) {
const negateWord = keywords[i].startsWith('-') ? true : false
let word = keywords[i].replace(/^-/,'')
const isPhraseRegex = word.startsWith('"') ? true : false
if (isPhraseRegex) {
word = word.replace(/^"(.+)"$/,"")
}
let word_in_item = false
for (const field of fields) {
if (item[field] && matchOrIncludes(item[field].toLocaleLowerCase(), word, isPhraseRegex)) {
word_in_item = true
break
}
}
if ((! negateWord && ! word_in_item) || (negateWord && word_in_item)) {
return false
}
}
return true
}
const item = {title: 'My title', body: 'Some text'}
console.info(itemMatches(item, 'text', ['title', 'body']))
Единственная проблема с этим состоит в том, что все кавычки удаляются, т. Е. Сами символы кавычек недоступны для поиска.