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

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

Пример:

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

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

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

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
9
0
19 450
10
Перейти к ответу Данный вопрос помечен как решенный

Ответы 10

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

Единственная проблема с этим состоит в том, что все кавычки удаляются, т. Е. Сами символы кавычек недоступны для поиска.

AC 15.09.2008 22:47

Хорошо, только не найти цитату из scape, например: ['foo', 'bar', 'lorem \' ipsum ',' baz ']

Wagner Pereira 21.12.2018 00:10

отлично! это простой способ реализовать синтаксический анализатор поисковой системы для поиска фраз и отдельных слов ... очень признателен!

Brad Parks 08.03.2019 20:02

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

Rob Hawkins 20.10.2020 18:02

Попробуй это:

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

Это не поддерживает Юникод, например, не поддерживает арабские символы.

Farzad Yousefzadeh 05.10.2018 21:59

Решение 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' ]

Продолжая принятый ответ, вот синтаксический анализатор поисковой системы, который,

  • может соответствовать фразам или словам
  • обрабатывает фразы как регулярные выражения
  • выполняет логическое ИЛИ для нескольких свойств (например, item.title и item.body)
  • обрабатывает отрицание слов или фраз, когда они начинаются с префикса -

Обработка фраз как регулярных выражений упрощает пользовательский интерфейс для моих целей.

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']))

Другие вопросы по теме