如何使用正则表达式匹配重叠关键词

4
这个例子只能找到sam。如何使它能找到samsamwise两个单词?
var regex = /sam|samwise|merry|pippin/g;
var string = 'samwise gamgee';
var match = string.match(regex);
console.log(match);

注意:这只是一个简单的例子,但我的实际正则表达式是通过同时连接500个关键字创建的,因此搜索所有重叠并制作像/sam(wise)/之类的特殊情况太麻烦了。我能想到的另一种明显解决方案是单独迭代所有关键词,但我认为必须有一个快速优雅、单一的正则表达式解决方案。

你所说的“查找”具体指什么?也就是说,你将如何使用这些结果? - melpomene
我希望得到 ['sam', 'samwise'] 作为结果。 - Alexander Vasenin
5个回答

2
你可以使用带有捕获组的前瞻正则表达式来匹配这种重叠的情况:
var regex = /(?=(sam))(?=(samwise))/;
var string = 'samwise';
var match = string.match( regex ).filter(Boolean);
//=> ["sam", "samwise"]
  • 不要在正则表达式中使用g(全局)标志非常重要。
  • filter(Boolean)用于从匹配的数组中删除第一个空结果。

这要求所有关键字在同一偏移量处同时匹配,即所有关键字必须是彼此的前缀。 - melpomene
字符串可以是任何内容,如果它是“merry and samwise are friends”,我希望它匹配["sam", "samwise", "merry"]。 - Alexander Vasenin
1
在这种情况下,(?=.*?(merry))(?=.*?(sam))(?=.*?(samwise)) 将适用于您。 - anubhava
2
抱歉,这个版本无法处理“merry”输入。原来这是一个对于正则表达式来说非常困难的情况。我感觉自己像特鲁曼一样撞到了世界的墙上。 - Alexander Vasenin
嗯,JS正则表达式没有PCRE的花哨口味。我想你需要迭代循环并检查输入文本中的每个关键字。 - anubhava
显示剩余3条评论

1

为什么不直接在数组的子字符串上 map indexOf() 呢:

var string = 'samwise gamgee';
var substr = ['sam', 'samwise', 'merry', 'pippin'];

var matches = substr.map(function(m) {
  return (string.indexOf(m) < 0 ? false : m);
}).filter(Boolean);

查看示例 console.log(matches);

数组 [ "sam", "samwise" ]

可能比使用正则表达式更高效。但如果您需要正则表达式功能,例如不区分大小写匹配、单词边界、返回匹配项等,请与exec方法一起使用:

var matches = substr.map(function(v) {
  var re = new RegExp("\\b" + v, "i"); var m = re.exec(string); 
  return (m !== null ? m[0] : false);
}).filter(Boolean);

这个使用 i 标志(忽略大小写)返回每个以初始 \b 单词边界 匹配的第一个匹配项。


0
怎么样:
var re = /((sam)(?:wise)?)/;
var m = 'samwise'.match(re); // gives ["samwise", "samwise", "sam"]
var m = 'sam'.match(re);     // gives ["sam", "sam", "sam"]

您可以使用数组中的唯一值来删除重复项。


抱歉,您只是在尝试为重叠关键字实现一种特殊情况。想法是要平等地处理它们,无论是否重叠。 - Alexander Vasenin

0

如果您不想创建特殊情况,并且顺序不重要,为什么不先匹配完整名称:

\b(sam|samwise|merry|pippin)\b

然后,过滤掉一些不包含较短字符串的字符串?例如:

(sam|samwise|merry|pippin)(?=\w+\b)

虽然不是最优美的正则表达式,但比起遍历所有匹配项而言,我认为它更加简单。


0

我想不出一个简单而优雅的解决方案,但我有一个使用单个正则表达式的东西:

function quotemeta(s) {
    return s.replace(/\W/g, '\\$&');
}

let keywords = ['samwise', 'sam'];

let subsumed_by = {};
keywords.sort();
for (let i = keywords.length; i--; ) {
    let k = keywords[i];
    for (let j = i - 1; j >= 0 && k.startsWith(keywords[j]); j--) {
        (subsumed_by[k] = subsumed_by[k] || []).push(keywords[j]);
    }
}

keywords.sort(function (a, b) b.length - a.length);
let re = new RegExp('(?=(' + keywords.map(quotemeta).join('|') + '))[\\s\\S]', 'g');

let string = 'samwise samgee';

let result = [];
let m;
while (m = re.exec(string)) {
    result.push(m[1]);
    result.push.apply(result, subsumed_by[m[1]] || []);
}

console.log(result);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接