解析字符串:提取单词和短语[JavaScript]

时间:2008-09-15 17:26:19

标签: javascript regex parsing

我需要在空格分隔的术语列表中支持精确短语(用引号括起来)。 因此,用空格字符分割相应的字符串是不够的。

示例:

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

我想知道这是否可以通过一个RegEx来实现,而不是执行复杂的解析或拆分和重新加入操作。

非常感谢任何帮助!

11 个答案:

答案 0 :(得分:15)

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

...返回您正在寻找的数组 但请注意:

  • 包含了绑定引号,因此可以在结果上使用replace(/^"([^"]+)"$/,"$1")删除。
  • 引号之间的空格将保持不变。因此,如果loremipsum之间有三个空格,则它们将出现在结果中。您可以通过在结果上运行replace(/\s+/," ")来解决此问题。
  • 如果"之后没有结束ipsum(即错误引用的词组),您最终会得到:['foo', 'bar', 'lorem', 'ipsum', 'baz']

答案 1 :(得分:3)

试试这个:

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

答案 2 :(得分:1)

怎么样,

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

然后对输出传递以丢失引号。

交替,

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

然后执行pass n输出以丢失空捕获。

答案 3 :(得分:1)

非常感谢您的快速回复!

以下是后人的选项摘要:

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);

答案 4 :(得分:0)

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

虽然

包含了边界引号

答案 5 :(得分:0)

一个简单的正则表达式可以但保留引号。 e.g。

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

编辑:shyamsundar殴打它,对不起双重答案

答案 6 :(得分:0)

如果您只是想知道如何自己构建正则表达式,您可能需要查看Expresso(Expresso link)。这是学习如何构建正则表达式的好工具,因此您可以了解语法的含义。

当您构建自己的表达式时,可以对其执行.match

答案 7 :(得分:0)

易于理解和一般解决方案。适用于所有分隔符和“加入”字符。还支持长度超过两个单词的“连接”单词....即

之类的列表

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

答案 8 :(得分:0)

这可能是一个非常晚的答案,但我有兴趣回答

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

答案 9 :(得分:0)

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

答案 10 :(得分:0)

扩展接受的答案,这是一个搜索引擎解析器,

  • 可以匹配短语或单词
  • 将短语作为正则表达式
  • 对多个属性(例如item.title和item.body)进行布尔OR
  • 以-开头的单词或短语的否定处理

将短语作为正则表达式进行处理可以使UI更加简单。

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(/^"(.+)"$/,"$1")
    }
    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.log(itemMatches(item, 'text', ['title', 'body']))