我有一个80,000多个单词的列表,每个单词用换行符分隔。我需要匹配包含一个较小单词作为其前缀的每个单词。例如,
bald <-- captures bald
balder <-- matches because it starts with bald
balding <-- matches because it starts with bald
care <-- captures care
cared <-- matches because it starts with care
cares <-- matches because it starts with care
caring <-- does NOT match because it does not start with care
我将使用find&amp;替换为崇高文本,以便我能够用#34;&#34;来替换所有匹配。从我的列表中删除它们。
好的,这是背景故事:
我的单词列表基本上是英语词典的删节版本。使用正则表达式我已经能够删除所有专有名词,缩写词,带重音字符的单词以及长度小于4个字母的所有单词。我将这个词典用于我正在制作的javascript文字游戏。 (是的,这个是用于作业,但它不用于学校学分,而且作业很简单,可以进行简单的javascript游戏。我的游戏逻辑有效,我可以手动编辑单词列表,但我希望它能在2016年之前完成,所以正则表达式似乎是要走的路。)
游戏的目的是强迫你的对手拼写一个单词。玩家轮流在字符串中添加字母,一旦字符串与字典中的单词匹配,游戏玩法就会结束。出于这个原因,夸张,头顶和过度杀伤等词语都是重量级的。一旦结束了开销,游戏就是......好吧...... over 。
我将wordList作为一个数组加载到javascript文件中,所以我希望它尽可能小。
我确定还有其他方法可以做到这一点(api&#39; s等),但我们无法将它们用于此任务。
非常感谢任何帮助!
答案 0 :(得分:3)
存储单词列表的有效结构是prefix tree。例如,给出像
这样的字典'car',
'card',
'carder',
'care',
'cared',
'cares',
'caring',
'can'
特里可能看起来像这样
(其中0
表示单词的结尾)。
构建trie的代码非常简单:
function buildTree(words) {
var tree = {};
words.forEach(function (word) {
var t = tree;
[].forEach.call(word + "0", function (char) {
t = t[char] || (t[char] = {});
});
});
return tree;
}
现在,要枚举以给定前缀开头的所有单词,只需递归地遍历trie并收集匹配的单词:
function findWords(prefix, tree) {
var found = [];
function walk(pfx, t, word) {
if (!pfx) {
if (t[0])
found.push(word)
for (var c in t)
walk("", t[c], word + c);
} else if (pfx[0] in t)
walk(pfx.substr(1), t[pfx[0]], word + pfx[0]);
}
walk(prefix, tree, "");
return found;
}
完整代码:
function buildTree(words) {
var tree = {};
words.forEach(function (word) {
var t = tree;
[].forEach.call(word + "0", function (char) {
t = t[char] || (t[char] = {});
});
});
return tree;
}
function findWords(prefix, tree) {
var found = [];
function walk(pfx, t, word) {
if (!pfx) {
if (t[0])
found.push(word)
for (var c in t)
walk("", t[c], word + c);
} else if (pfx[0] in t)
walk(pfx.substr(1), t[pfx[0]], word + pfx[0]);
}
walk(prefix, tree, "");
return found;
}
words = [
'car',
'card',
'carder',
'care',
'cared',
'cares',
'caring',
'can'
]
prefixTree = buildTree(words);
document.write(findWords("care", prefixTree));
要删除以其他单词开头的单词,您可以像上面一样构建trie然后再行走,一旦找到终端标记(0
)就切断搜索:
function buildTree(words) {
var tree = {};
words.forEach(function (word) {
var t = tree;
[].forEach.call(word + "0", function (char) {
t = t[char] || (t[char] = {});
});
});
return tree;
}
function findShortWords(tree) {
var found = [];
function walk(t, word) {
if(t[0]) {
found.push(word);
return;
}
for (var c in t)
walk(t[c], word + c);
}
walk(tree, "");
return found;
}
words = [
'card',
'carder',
'care',
'cared',
'cares',
'caring',
'can',
'canoe',
'bald',
'balder',
'balding',
'foo'
]
prefixTree = buildTree(words);
document.write(findShortWords(prefixTree));
答案 1 :(得分:3)
如果您可以先对单词列表进行反向排序,那么可以使用RegExp来帮助您。到目前为止,我只在我的iPod上用JavaScript替换它测试它,但我相信Sublime Text应该能够做同样的事情。这是我的示例文本(添加了一些额外的单词以加强它...):
var s="runs,running,runner,run,forging,forgetting,forgets,forget,forged,forge,caring,cares,cared,care,balding,balder,bald"
我将很快将其转换为由换行符分隔的单词列表,然后应用我的RegExp:
s=s.replace(/,/g,'\n');
s.replace(/(\w+)\w+\n(?=(?:.*\n)*\1(?:\n|$))/g,'');
这将删除所有&#34;不需要的&#34;完全划线并让你
run
forge
caring
care
bald
但是,如果您仍然需要空行代替您可以执行的不需要的单词
s.replace(/(\w+)\w+(?=\n(?:.*\n)*\1(?:\n|$))/g,'');
反向单词顺序对我的方法至关重要,因为我正在使用可变长度的前瞻来寻找单词的基本形式,而我可能在主模式中捕获它的变形形式{{1 }}。有趣的是,我从不相信它会像这样工作,但确实如此!线的捕获和非捕获部分没有明确定义,但RegExp引擎尝试不同的长度,直到在前瞻模式(\w+)\w+
中找到捕获组。在我的JavaScript示例中,设置RegExp的\n(?:.*\n)*\1(?:\n|$)
标志就足够了。在Sublime文本中,您很可能还必须设置相当于g
的多行标记。
你可能已经注意到整个方法中仍然存在一个基本缺陷:干&#34;锻造&#34;它不仅消灭了自己的其他动词形式,而且还带走了所有形式的“忘记”。这是一个&#34;逻辑&#34;问题与基本动词形式从未在一个简单的单词列表中明确定义这一事实有关。
<强>更新强>
再次阅读你的问题。为了你的游戏的目的,基本的缺陷&#34;实际上是你想要的东西。所以请忽略我的最后一段。 ; - )
答案 2 :(得分:1)
我认为所有单词都是小写的,所以我们不必关心区分大小写。
第1步
将光标放在文档中的任意位置(不选择任何内容)并按 F9 (或从菜单编辑&gt;排序行)对单词列表进行排序。
第2步
使用以下正则表达式搜索:
^(.*)\R(\1.*$\R?)+
并替换为:
$1\n
我希望您了解read
和readdress
等案例,其中readdress
将从read
开始删除,尽管这两个字段没有任何内容互相帮助。