如何使用正则表达式提取布尔运算符后跟单词直到下一个运算符?

How to use regex to extract boolean operators followed by words until the next operator?

我正在尝试组合一个相对简单的表达式,用于从用户输入中提取布尔字符串运算符(AND、OR、NOT 等),结果匹配数组将包含单词和前面的运算符直到下一个运算符:

const query = 'lorem AND ipsum dolor OR fizz NOT buzz';

结果应该是这样的:

[
 ['AND', 'ipsum dolor'],
 ['OR', 'fizz'],
 ['NOT', 'buzz']
]

我创建这个是为了在每个运算符之后获取单个单词,这很好:

^(\w+\s?)+?|(AND) (\w+)|(OR) (\w+)|(NOT) (\w+)

然后尝试修改它来处理运算符后的多个单词以获得上述结果,但它总是贪婪并捕获整个字符串输入:

(AND|OR|NOT) (\w+\s?)+ (?:AND|OR|NOT)

更新

我已经弄明白了,但我不确定它有多漂亮或高效:

^(\w+)|(AND|OR|NOT) (.*?(?= AND|OR|NOT))|(AND|OR|NOT) .*?$

我无法用正则表达式做到这一点,但这是一个可以工作的超级简单的解决方案。

let q = 'lorem AND ipsum dolor OR fizz NOT buzz';
let special = ['AND', 'OR', 'NOT'];

let fullResult = [];
let skip = true;

q.split(' ').forEach( word => {
    if ( special.indexOf(word) !== -1 ) {
        fullResult.push([word]);
        skip = false;
    } else if (!skip){
        fullResult[fullResult.length-1].push(word);
    }
});

console.log(fullResult);

您也可以使用否定前瞻来断言 so 之后的单词字符不以任何一个备选方案开头

\b(AND|OR|NOT) ((?!AND|OR|NOT)\b\w+(?: (?!AND|OR|NOT)\w+)*)

Regex demo

const regex = /\b(AND|OR|NOT) ((?!AND|OR|NOT)\b\w+(?: (?!AND|OR|NOT)\w+)*)/gm;
const str = `lorem AND ipsum dolor OR fizz NOT buzz`;
let m;
let result = [];
while ((m = regex.exec(str)) !== null) {
  result.push([m[1], m[2]]);
}
console.log(result);

我不认为你可以 纯粹 使用 JavaScript 中的正则表达式,但你可以非常接近:

const query = 'lorem AND ipsum dolor OR fizz NOT buzz';
const rex = /\b(AND|OR|NOT|NEAR)\b\s*(.*?)\s*(?=$|\b(?:AND|OR|NOT|NEAR)\b)/ig;
const result = [...query.matchAll(rex)].map(([_, op, text]) => [op, text]);
console.log(result);

正则表达式 /\b(AND|OR|NOT|NEAR)\b\s*(.*?)\s*(?=$|\b(?:AND|OR|NOT|NEAR)\b)/ig 查找:

  • 分词
  • 你的一个操作员(捕获它)
  • 分词
  • 零个或多个空白字符(捕获它们)
  • non-greedy 匹配任何内容
  • 零个或多个空白字符
  • 另一个运算符或字符串的结尾

matchAll 调用之后的 map 只是用于删除初始数组条目(具有匹配全文的条目)。我已经用解构完成了,但你可以使用 slice 代替:

const result = [...query.matchAll(rex)].map(match => match.slice(1));

const query = 'lorem AND ipsum dolor OR fizz NOT buzz';
const rex = /\b(AND|OR|NOT|NEAR)\b\s*(.*?)\s*(?=$|\b(?:AND|OR|NOT|NEAR)\b)/ig;
const result = [...query.matchAll(rex)].map(match => match.slice(1));
console.log(result);