簡體   English   中英

正則表達式(Javascript) - 取一個擾亂的單詞並找到一個解密的匹配

[英]Regular Expression (Javascript) - Take a scrambled word and find an unscrambled match

我的所有的英文字典存儲在一個名為變量的話(270,000+字)列表theList 我有一個炒字word ,我想對單詞列表匹配解讀。 最初,我認為以下代碼可以解決問題,但它不能很好地工作。

var theList; // Contains all the words in the English dictionary.

var word = "iexospensr"; // The word I want to unscramble.

var matches = word.match(new RegExp("^["+word+"]{"+word.length+"}$", "gim"));

我已經預期“EXPRESSION”作為解讀結果,但我得到了更多的結果(如下所列)。

EERINESSES,EXPRESSERS,EXPRESSION,IRONNESSES,ISOSPORIES,NONPERSONS,NONPROSSES,NOSINESSES,OPENNESSES,OPPRESSION,OPPRESSORS,ORNERINESS,PENSIEROSO,PENSIONEER,PENSIONERS,PEPPERONIS,PERSIENNES,PERSONISES,PIPINESSES,PIXINESSES,POORNESSES,PORINESSES,POSSESSION,POSSESSORS,PREEXPOSES,PREPOSSESS,PREPPINESS,PRESENSION,PRIORESSES,PRISSINESS,PROPENSION,PROPERNESS,REINSPIRES,REPRESSERS,REPRESSION,REPRESSORS,RESERPINES,RESPONSERS,RESPONSORS,RIPENESSES,ROPINESSES,ROSINESSES,SERENENESS,SEXINESSES,SIXPENNIES,SNIPPINESS,SORENESSES,SPINNERIES

也許,如果我能找到一種方法來告訴正則表達式只考慮字符串word中的每個字母,而不管字母的順序如何。 所以最終結果將是這些字母組合的數組,而不是排列(我現在擁有的)。

任何幫助,將不勝感激。


編輯:我認為要走的路是:1。找到擾亂的單詞的所有組合2.將它們與單詞列表匹配以檢查有效性

如果你有一個更好的解決方案(性能方面),它會有所幫助。


這個問題的最佳解決方案似乎是按字母順序重新排序字謎,以及整個單詞列表並將單詞與列表中的每個項目進行匹配。

這是代碼:

    var textList; // the entire dictionary
    var list = textList.match(/^.*$/gim);
    var sortedList = [];
    list.forEach(function(element, index, array) {
        sortedList[index] = element.split("").sort().join("");
    });

    function unscramble(word)
    {
        word = word.toUpperCase().split("").sort().join("");
        var matches = [];
        for (var i = 0; i < list.length; i++) {
            if (word.indexOf(sortedList[i]) >= 0) {
                if (!matches[list[i].length])
                    matches[list[i].length] = [];
                matches[list[i].length].push(list[i]);
            }
        }
        return matches;
    }

我認為更好的方法不會使用正則表達式。 相反,它會通過遍歷單詞的字符,並查看列表中的單詞是否存在,來測試列表中的每個成員與您的混亂單詞。 每次找到一個字符時,它都可以將該字符標記為“已經使用過”。

這是將字符位置標記為“已使用”的內容:

function checkUsed(o, which) {
if (o[which] != null) {
  o[which] = 1;
  return false;
  }
return true;
}


var usedMap = [];

if (checkUsed(usedMap, 5) == false) {
 ...
 }

這是給你的一個想法。 構造初始查找數據會很慢,但找到匹配應該很簡單。 但是,您應該只構建一次字典並加載它! 每次重新計算都是浪費時間。

  1. 我假設你只使用拉丁字母(即英文寫的是什么),一切都不區分大小寫,你不使用數字......等等。 所以你只有字符AZ。

  2. 對於詞典中的每個單詞,根據每個字母出現的計數構建“哈希”。 哈希數組將有26個位置。 每個位置將計算遇到該位置的特定字符的次數。 (例如,A位於第一個數組位置/索引0; Z位於第26個/索引25)
    為了作弊,你可以將結果存儲為一對字符串。 很少(如果有的話)單個字母重復9次,因此每個字母的單個“數字”應該可以正常工作。 例如:“the”變為“00001001000000000001000000”; “帽子”變成“10000001000000000001000000”; “那”變成“10000001000000000002000000”。

  3. 加載預先計算的字典。 將散列值用作鍵值對中的鍵,並將集合作為值。 將具有相同鍵的每個單詞附加到該鍵的集合的末尾。

  4. 對加擾的字執行相同的哈希算法,並查找密鑰。 輸出密鑰引用的集合。

編輯1:如果預先建立一個字典是不可行的,那么使用一個變體來創建一個以字母為鍵的關聯數組/字典,以及它作為值找到的次數。 在計算之前,比較長度,如果字符串長度不同,那么不要打擾比較,因為你知道它們不匹配。 為源(加擾)和目標(可能的匹配)計算這些數組后,比較關聯數組中的鍵和值。

編輯2:幾乎與上面相同的行,對源字符串和目標字符串的字符串中的字符進行排序。

不要使用正則表達式,有更簡單的方法,如果你將字典拆分成單詞而不是做一個巨大的字符串:

  1. 擾亂的單詞由字母出現的頻率定義:

     //WARNING, untested code alphabet = 'qwertyuiopasdfghjklzxcvbnm'; function empty_frequences(){ var freqs = {}; var i=; for(i=0; i<alphabet.length; i++){ freqs[alphabet[i]] = 0; } return freqs; } function frequences(str){ var freqs = empty_frequences(); var i; for(i=0; i<str.length; i++){ freqs[str[i]] += 1; } } 
  2. 使用此事實查找字典中的所有匹配項

     function matcher(word){ //returns a function that matchs against this word var word_freqs = frequences(word); function do_the_match(word2){ var freqs2 = frequences(word2); var i, c; for(i=0; i<alphabet.length; i++){ c = alphabet[i] if(freqs[c] > freqs2[c]){return false;} //change > to != to allow only strict anagrams } return true; } return do_the_match; } function main(word, dict){ var mf = matcher(word); var i, matcheds = []; for(i=0; i<dict.length; i++){ if(mf(dict[i])){ matcheds.push(dict[i]); } } return matcheds; } 

就是圖個好玩兒:

> var words = 'exceptional extraordinary retinas retains retsina antsier nastier retrains starfish';
> words.match(/\b([aeinrst])(?!\1)([aeinrst])(?!\1|\2)([aeinrst])(?!\1|\2|\3)([aeinrst])(?!\1|\2|\3|\4)([aeinrst])(?!\1|\2|\3|\4|\5)([aeinrst])(?!\1|\2|\3|\4|\5|\6)([aeinrst])\b/ig)
[ 'retinas', 'retains', 'retsina', 'antsier', 'nastier' ]

請注意,如果您有兩個相同的字母,我無法弄清楚如何使上述方法工作,例如我無法匹配“boo”:)

如果查詢必須快速,並且在開始時構建並不是一個大問題,那么使用Trie是我所知道的最有效的解決方案。 我可以解釋一下,但WP文章實際上非常好,並提供了代碼示例。

如果您主要關注2個給定的字符串是否匹配,那么使用直方圖的解決方案可能是最好的。

我不知道正則表達式是否是這項工作的最佳工具。 你正在建立的正則表達式最終將成為現實

"^[iexospensr]{10}$"

它匹配由字符類[iexospensr]任何字母組成的任何10個字母的單詞。

也許,如果我能找到一種方法來告訴正則表達式只考慮字符串單詞中的每個字母,而不管字母的順序如何。

你可以使用word.length不同的正則表達式,但你的一些字母重復。 如果你對擾亂的單詞中的字母進行排序,然后搜索每個字母具有正確重復次數的單詞,你就會越來越近。 例如,兩個e,兩個s,一個x等。

正則表達雖然功能強大,但並不能解決所有問題。

在某些情況下,建立自己的解決方案會更好:首先刪除所有與所需長度不匹配的單詞,然后開始比較字母。

根據字典的長度,您可以構建不同的優化。

我很久以前就應該看過這個問答了。 我一直在研究這個,我想分享我對這個問題的解決方案。

解決方案:第1步:按字母順序對加擾后的單詞進行排序(注意:甚至是本書的擾亂頁面)

第2步:構建您的WORD或PAGE列表,其中包含已排序單詞的附加列(注意:您可以根據需要對此列進行哈希)

第3步:完成匹配過程。 這應該從查找列表中找到加擾的單詞。

我正在做一些關於找到任意亂序的研究。 頁面中的單詞,並創建一個列表,其中包含給定擾亂字母的那些擾亂的單詞。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM