我试图根据用户输入列出给定字符串中的所有三字母(3个字母单词)。用户可以输入1,2或3个字符。我写了以下代码:
if (3 == trigram.length) {
var re = new RegExp(trigram);
} else if (2 == trigram.length) {
trigram = trigram + '\\S|\\S' + trigram;
var re = new RegExp(trigram);
} else if (1 == trigram.length) {
trigram = trigram + '\\S\\S|\\S\\S' + trigram + '|\\S' + trigram + '\\S';
var re = new RegExp(trigram);
} else {
alert("Trigram search pattern can be either one, two or three characters!");
return null;
}
var re = new RegExp(trigram, "ig"); alert(re);
trigramList = givenString.match(re);
这个工作正常,但是如果我的字符串“KDSGKHAGSKH”中有以下字符序列并且我正在搜索包含'A'的三元组我的代码只返回“KHA”,我希望它返回{KHA, HAG,AGS}
答案 0 :(得分:1)
以下是两个简单的功能,似乎是您正在寻找的功能
String.prototype.ngrams = function(n) {
var r = [];
for(var i = 0; i <= this.length - n; i++)
r.push(this.substring(i, i + n));
return r;
}
Array.prototype.grep = function(re) {
var r = [];
for(var i = 0; i < this.length; i++)
if(re.test(this[i]))
r.push(this[i]);
return r;
}
s = "abcdefghjkl";
alert(s.ngrams(3).grep(/d/))
打印“bcd”,“cde”,“def”。不是最有效但最简单的。
答案 1 :(得分:1)
原始问题是正则表达式将成功匹配的结束设置为下一个匹配的开始位置,这意味着您无法轻松获得重叠匹配。您需要找到一种方法来使匹配的字符串恰好一个字符长,这样起始索引总是比以前成功匹配的开头多一个。您可以通过积极的前瞻来做到这一点,并使用捕获组来获得与前瞻相匹配的任何内容。
var onegram = /A(?=(\S\S))|\S(?=(\SA))|\S(?=(A\S))/ig;
var str = 'KDSGKHAGSKH';
var match
var ngrams = [];
while ((match = onegram.exec(str)) != null) {
ngrams.push(match.join(''));
}
你可以在String上使用一个额外的方法,相当简单地生成RE(虽然效率不是最好):
String.prototype.repeat = function (n) {
if (n<1) return '';
var accum = '', c=this;
for (; n; n >>=1) {
if (1&n) accum += c;
c += c;
}
return accum;
};
function ngrammer(kgram, n) {
var m = n - kgram.length;
var branches = [];
for (var i = 0; i <= m; ++i) {
branches.push(('\\S'.repeat(i) + kgram + '\\S'.repeat(m-i) + '))').replace(/^\\?./, '$&(?=('));
}
return new RegExp(branches.join('|'), 'ig');
}
var onegram = ngrammer('A', 3);
...