我希望有人知道一个脚本,可以获取任意单词列表并生成最短的正则表达式,以完全匹配该列表(不匹配其他内容)。
例如,假设我的列表是:
例如,假设我的列表是:
1231
1233
1234
1236
1238
1247
1256
1258
1259
那么输出结果应该是:
12(3[13468]|47|5[589])
1231
1233
1234
1236
1238
1247
1256
1258
1259
那么输出结果应该是:
12(3[13468]|47|5[589])
|
分隔的输入字符串列表组成,并输出一个最优的正则表达式。perl -mRegexp::Optimizer -e "print Regexp::Optimizer->new->optimize(qr/1231|1233|1234|1236|1238|1247|1256|1258|1259/)"
(?^:(?^:12(?:3[13468]|5[689]|47)))
Regex::Optimizer
),这很好地满足了OP的期望。perl -mRegexp::Optimizer -e "print Regexp::Optimizer->new->optimize(qr/314|324|334|3574|384/)"
输出结果:
(?^:(?^:3(?:[1238]|57)4))
作为对比,一个最佳的基于字典树的版本将输出 3(14|24|34|574|84)
。在上面的输出中,您还可以搜索并替换 (?:
和 (?^:
为 (
,消除冗余的括号,以获得如下结果:
3([1238]|57)4
您最好将整个列表保存下来,如果您想变得更加高级一些,可以创建一个Trie:
1231
1234
1247
1
|
2
/ \
3 4
/ \ \
1 4 7
12
)。
2. 分支创建|
:(例如:12(3|4)
)
3. 叶节点生成一个字符类(或单个字符),该字符类遵循父节点:(例如12(3[14]|47)
)[12345]
变成[1-4]
)。
2. 为重复元素添加量词符号(例如:[1234][1234]
变成[1234]{2}
)。
3. ???|
", 非捕获组 "(?:)
" 和选项 "?
"。
当有一排单个字符时,还有改进的空间:
例如,(?:3|8|1|6|4)
可以生成 [38164]
。java -jar dist/wordhierarchy.jar 1231 1233 1234 1236 1238 1247 1256 1258 1259
-> 12(?:5(?:6|9|8)|47|3(?:3|8|1|6|4))
var list = new listChar("");
function listChar(s, p) {
this.char = s;
this.depth = 0;
this.parent = p;
this.add = function(n) {
if (!this.subList) {
this.subList = {};
this.increaseDepth();
}
if (!this.subList[n]) {
this.subList[n] = new listChar(n, this);
}
return this.subList[n];
}
this.toString = function() {
var ret = "";
var subVals = [];
if (this.depth >=1) {
for (var i in this.subList) {
subVals[subVals.length] = this.subList[i].toString();
}
}
if (this.depth === 1 && subVals.length > 1) {
ret = "[" + subVals.join("") + "]";
} else if (this.depth === 1 && subVals.length === 1) {
ret = subVals[0];
} else if (this.depth > 1) {
ret = "(" + subVals.join("|") + ")";
}
return this.char + ret;
}
this.increaseDepth = function() {
this.depth++;
if (this.parent) {
this.parent.increaseDepth();
}
}
}
function wordList(input) {
var listStep = list;
while (input.length > 0) {
var c = input.charAt(0);
listStep = listStep.add(c);
input = input.substring(1);
}
}
words = [/* WORDS GO HERE*/];
for (var i = 0; i < words.length; i++) {
wordList(words[i]);
}
document.write(list.toString());
使用
words = ["1231","1233","1234","1236","1238","1247","1256","1258","1259"];
(1(2(3[13468]|47|5[689])))
()
的数量:http://jsfiddle.net/6NhcV/1/ 这样就得到了 (12(3[13468]|47|5[689]))
。 - Arnaud Le Blanc
12[13-9]\{2\}
吗? - Manny D