正则表达式以任何顺序匹配查询中的所有单词

kay*_*yen 27 javascript regex jquery

我正在尝试为项目构建搜索功能,该项目根据用户搜索输入缩小项目,如果匹配项目列出的关键字.为此,我将项目关键字保存在data属性中,并使用RegExp模式将查询与这些关键字匹配.

我目前正在使用这个表达式,我知道这是不正确的,需要你的帮助:

new RegExp('\\b(' + query + ')', 'gi')))其中query是|用户输入的查询的分隔值(例如\\b(meat|pasta|dinner)).即使只有一场比赛,这也会给我一个匹配,比如说 - meat

只是为了抛出一些背景,这是一个小例子:

如果用户键入:meat pasta dinner它应列出所有列出所有3个关键字的项目,即meat pastadinner.这些与他们输入的顺序无关.

你能帮我一个表达式,它会以任何顺序匹配查询中的所有单词吗?

ste*_*ema 56

你可以实现这一前瞻性断言

^(?=.*\bmeat\b)(?=.*\bpasta\b)(?=.*\bdinner\b).+
Run Code Online (Sandbox Code Playgroud)

在Regexr上看到它

(?=.*\bmeat\b)是一个积极的先行断言,确保它\bmeat\b在字符串中的某个位置.其他关键字相同,.+然后实际匹配整个字符串,但仅当断言为真时.

但它也将与"晚餐肉Foobar面食"相匹配


Sid*_*dex 10

Stema的答案在技术上是正确的,但它根本没有考虑性能。前瞻非常慢(在正则表达式的上下文中,速度快如闪电)。即使按照当前的逻辑,正则表达式也不是最优的。

以下是一些测量结果,是根据包含所有三个单词的较大字符串计算得出的,运行搜索 1000 次并使用四种不同的方法:

Stema的正则表达式

/^(?=.*\bmeat\b)(?=.*\bpasta\b)(?=.*\bdinner\b).+/

结果:605ms

优化的正则表达式

/^(?=.*?\bmeat\b)(?=.*?\bpasta\b)(?=.*?\bdinner\b)/

使用惰性匹配并且不需要结束所有选择器

结果:291ms

排列正则表达式

/(\bmeat\b.*?(\bpasta\b.*?\bdinner\b|\bdinner\b.*?\bpasta\b)|\bpasta\b.*?(\bmeat\b.*?\bdinner\b|\bdinner\b.*?\bmeat\b)|\bdinner\b.*?(\bpasta\b.*?\bmeat\b|\bmeat\b.*?\bpasta\b))/

结果:56ms

这很快,因为第一个模式匹配,如果最后一个模式匹配,它会比前瞻模式更慢(300 ms)

正则表达式数组

var regs=[/\bmeat\b/,/\bpasta\b/,/\bdinner\b/];
var result = regs.every(reg=>reg.test(text));
Run Code Online (Sandbox Code Playgroud)

结果:26ms

请注意,如果字符串被设计为不匹配,则结果为:

  • 521毫秒
  • 220毫秒
  • 161ms - 慢得多,因为它必须经过所有分支
  • 14毫秒

正如您所看到的,在所有情况下,仅使用循环都会快一个数量级,更不用说更容易阅读了。

最初的问题是要求一个正则表达式,所以我的答案是排列正则表达式,但我不会使用它,因为它的大小会随着搜索词的数量呈指数增长。

另外,在大多数情况下,这个性能问题是学术性的,但有必要强调一下。


Col*_*der 5

你的正则表达式看起来不错:

\b(meat|pasta|dinner)\b
Run Code Online (Sandbox Code Playgroud)

检查匹配的长度是否等于关键字的数量(在本例中为三个):

string.match(re).length === numberOfKeywords
Run Code Online (Sandbox Code Playgroud)

哪里re是带g标志的正则表达式,string是数据,numberOfKeywords是关键字的数量

这假设没有重复的关键字。

  • 在此模型中,重复项也需要删除 (2认同)