Строки синтаксического анализа: извлечение слов и фраз [JavaScript]

Мне нужно поддерживать точные фразы (заключенные в кавычки) в другом списке терминов, разделенных пробелами. Таким образом, расщепление соответствующей строки пространственным символом уже недостаточно.

Пример:

input : 'foo bar "lorem ipsum" baz'
output: ['foo', 'bar', 'lorem ipsum', 'baz']

Интересно, может ли это быть достигнуто с помощью одного RegEx, а не для выполнения сложных операций синтаксического анализа или разделения и повторного присоединения.

Любая помощь будет принята с благодарностью!

Ответ 1

var str = 'foo bar "lorem ipsum" baz';  
var results = str.match(/("[^"]+"|[^"\s]+)/g);

... возвращает массив, который вы ищете.
Обратите внимание, однако:

  • Связанные кавычки включены, поэтому их можно удалить с помощью replace(/^"([^"]+)"$/,"$1").
  • Пробелы между кавычками остаются неизменными. Итак, если между lorem и ipsum есть три пробела, они будут в результате. Вы можете исправить это, выполнив replace(/\s+/," ") по результатам.
  • Если закрытие " после ipsum (т.е. неверно цитируемая фраза), вы получите: ['foo', 'bar', 'lorem', 'ipsum', 'baz']

Ответ 2

Попробуйте следующее:

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"]

Ответ 3

как насчет,

output = /(".+?"|\w+)/g.exec(input)

затем выполните проход на выходе, чтобы потерять кавычки.

попеременно,

output = /"(.+?)"|(\w+)/g.exec(input)

затем выполните вывод pass n, чтобы потерять пустые записи.

Ответ 4

Большое спасибо за быстрые ответы!

Здесь приведено краткое описание вариантов, для потомков:

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.log("start:", terms[i]);
            buffer.push(terms[i].substr(1));
        } else { // end of phrase
            //console.log("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.log("cont'd:", terms[i]);
        buffer.push(terms[i]);
    } else { // individual term
        //console.log("standalone:", terms[i]);
        items.push(terms[i]);
    }
    //console.log(items, "\n", buffer);
}
items = items.concat(buffer);

//console.log(items);

Ответ 5

'foo bar "lorem ipsum" baz'.match(/"[^"]*"|\w+/g);

ограничивающие кавычки включаются, хотя

Ответ 6

Простое регулярное выражение будет делать, но оставить кавычки. например.

'foo bar "lorem ipsum" baz'.match(/("[^"]*")|([^\s"]+)/g)
output:   ['foo', 'bar', '"lorem ipsum"', 'baz']

изменить: избить его shyamsundar, извините за двойной ответ

Ответ 7

Если вам просто интересно, как самому создать регулярное выражение, вы можете проверить Expresso (ссылка Expresso). Это отличный инструмент, чтобы узнать, как создавать регулярные выражения, чтобы вы знали, что означает синтаксис.

Когда вы создали собственное выражение, вы можете выполнить < <20 > на нем.

Ответ 8

То, что легко понять и общее решение. Работает для всех разделителей и символов "присоединиться". Также поддерживает "соединенные" слова длиной более двух слов... т.е. Списки, такие как

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

Ответ 9

Это может быть очень поздний ответ, но я заинтересован в ответе

([\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"]

Ответ 10

Решение 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(/\\(.)/,"$1");
        }
        return  p;
    }, {a: ['']}).a

Вывод:

[ 'foo', 'bar', 'lorem ipsum', 'baz' ]