正则表达式以匹配包含任意顺序的两个名称的字符串

我需要逻辑和在正则表达式。

类似的

杰克和詹姆斯

同意以下字符串

  • 'hi jack here is james'

  • 'hi james here is jack'

299029 次浏览

试一试:

james.*jack

如果你同时想要两者,那么or它们:

james.*jack|jack.*james

你可以:

\bjack\b.*\bjames\b|\bjames\b.*\bjack\b

你可以使用积极的超前进行检查。下面是必不可少的regular-expressions.info的摘要:

前面看和后面看,统称为“回头看” 长度为零的断言…Lookaround实际上是匹配字符的,但是 然后放弃匹配,只返回结果:匹配或不匹配。 这就是为什么它们被称为“断言”。他们不消费 字符串中的字符,但仅断言是否可能匹配 。< / p >

然后,它继续解释正查找头用于断言,以便在匹配表达式中匹配某个没有占用了字符的表达式。

因此,下面是一个表达式,它使用两个后续的正查找头来断言短语以任意顺序匹配jackjames:

^(?=.*\bjack\b)(?=.*\bjames\b).*$

测试一下

括号中以?=开头的表达式是正的lookhead。我将分解这个模式:

  1. ^断言要匹配的表达式的开始。
  2. (?=.*\bjack\b)是第一个正向前向,表示后面的内容必须匹配.*\bjack\b
  3. .*表示任意字符0次或多次。
  4. \b表示任何单词边界(空白,表达式的开始,表达式的结束等)。
  5. jack字面上是一行中的四个字符(下一个正向前向中的james也是如此)。
  6. $声明匹配的表达式的结尾。

因此第一个前向查找说“;后面的内容(本身不是前向查找或后向查找)必须是一个表达式,以0个或多个任意字符开头,后跟一个单词边界,然后是jack和另一个单词边界,”;而前面的第二个look说“;接下来的表达式必须以0个或多个字符开头,后面跟着一个单词边界,然后是james和另一个单词边界。”在两个lookhead之后是.*,它简单地匹配任何字符0次或多次,以及$,它匹配表达式的结尾。

“以任何事情开始,然后杰克或詹姆斯,然后以任何事情结束”;它满足第一个前向,因为有许多字符,然后是单词jack;它满足第二个前向,因为有许多字符(恰好包括jack,但这不是满足第二个前向所必需的),然后是单词james。这两种前向都不会断言表达式的结束,因此后面的.*可以超出满足头向的内容,例如",然后以任何东西结束"。

我认为你已经明白了,但为了绝对清楚,这里是jackjames颠倒,即“以任何东西开始,然后是james或jack,然后以任何东西结束”;;它满足第一个前向,因为有许多字符,然后是单词james;它满足第二个前向,因为有许多字符(恰好包括james,但这对满足第二个前向不是必要的),然后是单词jack。和前面一样,前向都没有断言表达式的结束,因此后面的.*可以超出满足前向的内容,例如“;然后以任何东西结束”;

这种方法的优点是可以轻松指定多个条件。

^(?=.*\bjack\b)(?=.*\bjames\b)(?=.*\bjason\b)(?=.*\bjules\b).*$

我要写的命令说明: -

.表示任何字符,数字都可以代替。

*表示在它前面写的东西出现了零次或多次。

|表示”或“

所以,

james.*jack

将搜索james,然后搜索任意数量的字符,直到出现jack

自从你需要__ABC0或james.*jack

因此< < em >命令/ em >:

jack.*james|james.*jack

它又短又甜

(?=.*jack)(?=.*james)

测试用例:

[
"xxx james xxx jack xxx",
"jack xxx james ",
"jack xxx jam ",
"  jam and jack",
"jack",
"james",
]
.forEach(s => console.log(/(?=.*james)(?=.*jack)/.test(s)) )

Vim有一个分支操作符\&,它在搜索包含一组单词的行时非常有用,以任何顺序。此外,扩展所需的单词集是微不足道的。

例如,

/.*jack\&.*james

将以任意顺序匹配包含jackjames的行。

有关用法的更多信息,请参见这个答案。我不知道有任何其他实现分支的正则表达式;该操作符甚至没有在正则表达式维基百科条目中被记录。

答案中的表达式任何顺序中的一个jack和一个james执行此操作。

在这里,我们将探索其他场景。

方法1:一个jack和一个james

以防万一,两个jack或两个james是不允许的,只有一个jack和一个james是有效的,我们可以设计一个类似于:

^(?!.*\bjack\b.*\bjack\b)(?!.*\bjames\b.*\bjames\b)(?=.*\bjames\b)(?=.*\bjack\b).*$

在这里,我们将使用以下语句排除这些实例:

(?!.*\bjack\b.*\bjack\b)

而且,

(?!.*\bjames\b.*\bjames\b)

RegEx Demo 1

我们还可以将其简化为:

^(?!.*\bjack\b.*\bjack\b|.*\bjames\b.*\bjames\b)(?=.*\bjames\b|.*\bjack\b).*$

RegEx Demo 2


如果你想简化/更新/探索表达式,它在regex101.com的右上方面板中有解释。如果你感兴趣,你可以查看匹配的步骤或在这个调试器link中修改它们。调试器演示了一个正则表达式引擎如何一步步消耗一些示例输入字符串并执行匹配过程。


RegEx电路

jex.im可视化正则表达式:

enter image description here

测试

const regex = /^(?!.*\bjack\b.*\bjack\b|.*\bjames\b.*\bjames\b)(?=.*\bjames\b|.*\bjack\b).*$/gm;
const str = `hi jack here is james
hi james here is jack
hi james jack here is jack james
hi jack james here is james jack
hi jack jack here is jack james
hi james james here is james jack
hi jack jack jack here is james
`;
let m;


while ((m = regex.exec(str)) !== null) {
// This is necessary to avoid infinite loops with zero-width matches
if (m.index === regex.lastIndex) {
regex.lastIndex++;
}
    

// The result can be accessed through the `m`-variable.
m.forEach((match, groupIndex) => {
console.log(`Found match, group ${groupIndex}: ${match}`);
});
}


方法2:一个jack和一个james按照特定的顺序

表达式也可以先设计为james,再设计为jack,类似于下面的表达式:

^(?!.*\bjack\b.*\bjack\b|.*\bjames\b.*\bjames\b)(?=.*\bjames\b.*\bjack\b).*$

RegEx Demo 3

反之亦然:

^(?!.*\bjack\b.*\bjack\b|.*\bjames\b.*\bjames\b)(?=.*\bjack\b.*\bjames\b).*$

RegEx Demo 4

你可以使用regex的量词特性,因为lookaround可能不会一直被支持。

(\bjames\b){1,}.*(\bjack\b){1,}|(\bjack\b){1,}.*(\bjames\b){1,}

不需要两个超前,一个子字符串通常可以是匹配

^(?=.*?\bjack\b).*?\bjames\b.*

在regex101看到这个演示

查找是零长度断言(条件)。这里的前移检查^ < em > < / em >开始,如果jack出现在字符串的后面,如果成功则检查匹配,直到james.*,其余部分(可以被删除)。懒惰的 jack0用于单词之前(包含在\b jack1中)。对jack3使用jack2。