[英]Regex match if all characters in a dictionary word are present in the phrase. The number of times each character occurs must also match in each other
我正在編寫遞歸回溯搜索來查找短語的字謎。 第一步,我試圖在將字典提供給遞歸算法之前從字典中過濾掉所有錯誤的單詞。
字典文件如下所示:
aback
abacus
abalone
abandon
abase
...
[40,000 more words]
我要構建的正則表達式必須過濾掉包含短語不包含的字符的單詞,以及包含比短語中存在的字符更多的單詞。
例如,給定短語“clint eastwood”,單詞“noodle”匹配,但單詞“stonewall”不匹配,因為“stonewall”包含的“l”字符比“clint eastwood”包含的字符多。
簡單地使用"[clint eastwood]+"
作為正則表達式幾乎可以滿足我的要求,但它包含短語中包含任意數量字符的單詞。
正則表達式是比較字符數的錯誤工具。 任何滿足此要求的正則表達式都可能很笨拙且效率極低。 遍歷每個單詞並跟蹤單個字符數會更好。
無論如何,這里有一種構造匹配“錯誤單詞”的正則表達式的方法(反過來更難):首先,從短語中包含的一組不同字符{a1,...,aN}
中,您可以匹配包含任何非法字符的所有單詞[^a1,...,aN]
。 然后,對於在目標字符串中出現n
次的每個字符c
,構建一個子表達式(.*c.*){n+1}
,然后將這些片段與|
. 對於clint eastwood
,你應該得到:
(.*c.*){2}|(.*l.*){2}|(.*i.*){2}|(.*n.*){2}|(.*t.*){3}|(.*e.*){2}|(.*a.*){2}|(.*s.*){2}|(.*w.*){2}|(.*o.*){3}|(.*d.*){2}|[^clinteaswod]
如上一個答案所述,正則表達式不是您應該查看的內容。 您需要記錄每個單詞的字符數,以便稍后快速過濾無效行。 我有一個使用Map<String, Map<Character, Integer>>
的解決方案。
Map<String, Map<Character, Integer>> wordCharacterCount = new HashMap<>();
try (Scanner scanner = new Scanner(new File(...))) {
while (scanner.hasNextLine()) {
String word = scanner.nextLine();
Map<Character, Integer> characterCount = new HashMap<>();
char[] characters = word.toCharArray();
for (int i = 0; i < characters.length; i++) {
char c = Character.toLowerCase(characters[i]);
if (Character.isLetter(c)) {
if (!characterCount.containsKey(c)) {
characterCount.put(c, 1);
} else {
characterCount.put(c, characterCount.get(c) + 1);
}
}
}
wordCharacterCount.put(word, characterCount);
}
}
為簡單起見,我使用了 Stream API。 對於您想要過濾字典條目的每個短語,您構造一個類似的 Map<Character, Integer> 並遍歷 Map 以過濾條目,具體取決於它是否 (1) 包含無效字符或 (2) 具有更大的字符數比提供的短語。
String testWord = "clint eastwood";
char[] characters = testWord.toCharArray();
for (int i = 0; i < characters.length; i++) {
char c = Character.toLowerCase(characters[i]);
if (Character.isLetter(c)) {
if (!testWordCharacterCount.containsKey(c)) {
testWordCharacterCount.put(c, 1);
} else {
testWordCharacterCount.put(c, testWordCharacterCount.get(c) + 1);
}
}
}
List<String> validWords = wordCharacterCount.keySet().stream()
.filter(word -> {
Map<Character, Integer> currentWordCharacterCount = wordCharacterCount.get(word);
for (Entry<Character, Integer> entry : currentWordCharacterCount.entrySet()) {
char c = entry.getKey();
int count = entry.getValue();
if (!testWordCharacterCount.containsKey(c) || testWordCharacterCount.get(c) < count) {
return false;
}
}
return true;
}).collect(Collectors.toList());
我沒有對此進行徹底的基准測試,但在我的使用中,使用包含 460,000 個條目的字典,預處理需要大約 600 毫秒,過濾器每個需要大約 50-150 毫秒。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.