X-Git-Url: https://wannabe.guru.org/gitweb/?a=blobdiff_plain;f=unscrambler.py;h=3ccddbbea5ef3f59e3915c5046586e62f74f1182;hb=a9bdfd8fc9f84b7b2c09a57cd12ba32259e84d1c;hp=c5bc9b5f15200c0f909af2bd5f849be6fa60b809;hpb=5c212d7639f62fcb936f9d7a0bbe704a9f7b213d;p=python_utils.git diff --git a/unscrambler.py b/unscrambler.py index c5bc9b5..3ccddbb 100644 --- a/unscrambler.py +++ b/unscrambler.py @@ -1,5 +1,9 @@ #!/usr/bin/env python3 +# © Copyright 2021-2022, Scott Gasch + +"""A fast word unscrambler library.""" + import logging from typing import Dict, Mapping, Optional @@ -21,10 +25,10 @@ cfg.add_argument( logger = logging.getLogger(__name__) letters_bits = 32 -letters_mask = 2 ** letters_bits - 1 +letters_mask = 2**letters_bits - 1 fprint_bits = 52 -fprint_mask = (2 ** fprint_bits - 1) << letters_bits +fprint_mask = (2**fprint_bits - 1) << letters_bits fprint_feature_bit = { 'e': 0, @@ -98,15 +102,21 @@ class Unscrambler(object): lookup methods support a "fuzzy match" argument that can be set to request similar words that do not match exactly in addition to any exact matches. - """ def __init__(self, indexfile: Optional[str] = None): + """ + Constructs an unscrambler. + + Args: + indexfile: overrides the default indexfile location if provided + """ + # Cached index per instance. self.sigs = [] self.words = [] - filename = self.get_indexfile(indexfile) + filename = Unscrambler.get_indexfile(indexfile) with open(filename, 'r') as rf: lines = rf.readlines() for line in lines: @@ -116,7 +126,9 @@ class Unscrambler(object): self.sigs.append(isig) self.words.append(word) - def get_indexfile(self, indexfile: Optional[str]) -> str: + @staticmethod + def get_indexfile(indexfile: Optional[str]) -> str: + """Returns the current indexfile location.""" if indexfile is None: if 'unscrambler_default_indexfile' in config.config: indexfile = config.config['unscramble_indexfile'] @@ -172,6 +184,12 @@ class Unscrambler(object): the word and their frequencies. We try to cluster "similar" words close to each other in the signature space. + Args: + word: the word to compute a signature for + + Returns: + The word's signature. + >>> train = Unscrambler.compute_word_sig('train') >>> train 23178969883741 @@ -193,13 +211,17 @@ class Unscrambler(object): @staticmethod def repopulate( - lsigs: Dict[str, int], dictfile: str = '/usr/share/dict/words', indexfile: str = '/usr/share/dict/sparse_index', ) -> None: - """Before calling this method, change letter_sigs from the default above - unless you want to populate the same exact files. + """ + Repopulates the indexfile. + + .. warning:: + Before calling this method, change letter_sigs from the + default above unless you want to populate the same exact + files. """ words_by_sigs: Dict[int, str] = {} seen = set() @@ -225,10 +247,20 @@ class Unscrambler(object): """Looks up a potentially scrambled word optionally including near "fuzzy" matches. + Args: + word: the word to lookup + window_size: the number of nearby fuzzy matches to return + + Returns: + A dict of word -> bool containing unscrambled words with (close + to or precisely) the same letters as the input word. The bool + values in this dict indicate whether the key word is an exact + or near match. The count of entries in this dict is controlled + by the window_size param. + >>> u = Unscrambler() >>> u.lookup('eanycleocipd', window_size=0) {'encyclopedia': True} - """ sig = Unscrambler.compute_word_sig(word) return self.lookup_by_sig(sig, window_size=window_size) @@ -238,6 +270,18 @@ class Unscrambler(object): a previous call to Unscrambler.compute_word_sig. Optionally returns near "fuzzy" matches. + Args: + sig: the signature of the word to lookup (see :meth:`compute_word_sig` + to generate these signatures). + window_size: the number of nearby fuzzy matches to return + + Returns: + A dict of word -> bool containing unscrambled words with (close + to or precisely) the same letters as the input word. The bool + values in this dict indicate whether the key word is an exact + or near match. The count of entries in this dict is controlled + by the window_size param. + >>> sig = Unscrambler.compute_word_sig('sunepsapetuargiarin') >>> sig 18491949645300288339 @@ -245,7 +289,6 @@ class Unscrambler(object): >>> u = Unscrambler() >>> u.lookup_by_sig(sig) {'pupigerous': False, 'pupigenous': False, 'unpurposing': False, 'superpurgation': False, 'unsupporting': False, 'superseptuaginarian': True, 'purpurogallin': False, 'scuppaug': False, 'purpurigenous': False, 'purpurogenous': False, 'proppage': False} - """ ret = {} (_, location) = list_utils.binary_search(self.sigs, sig)