繁体   English   中英

如何将重叠关键字与正则表达式匹配

[英]How to match overlapping keywords with regex

此示例仅查找sam 如何使它查找这两个 samsamwise

var regex = /sam|samwise|merry|pippin/g;
var string = 'samwise gamgee';
var match = string.match(regex);
console.log(match);

注意:这是一个简单的例子,但是我的真正正则表达式是通过在时间上加入500个关键字来创建的,所以搜索所有重叠并使用/sam(wise)/类的东西为它们创建特殊情况太麻烦了。 我能想到的另一个明显的解决方案是单独迭代所有关键字,但我认为它必须是一个快速而优雅的单一正则表达式解决方案。

对于此重叠匹配,您可以使用前瞻性正则表达式捕获组:

var regex = /(?=(sam))(?=(samwise))/;
var string = 'samwise';
var match = string.match( regex ).filter(Boolean);
//=> ["sam", "samwise"]
  • 重要的是不要在正则表达式中使用g (全局)标志。
  • filter(Boolean)用于从匹配的数组中删除第一个空结果。

为什么不在数组substr上映射 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);

请参阅fiddle 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 -flag( 忽略大小写 )返回与初始的每个第一匹配\\b 字边界

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

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

怎么样:

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

您可以在数组中使用唯一值来删除dupplicates。

如果您不想创建特殊情况,并且订单无关紧要,为什么不首先只匹配全名:

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

然后,如果其中一些不包含较短的一个,过滤? 例如:

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

它不是一个优雅的正则表达式,但我认为它比迭代所有匹配更简单。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM