| 1709 | # Based on: Peter Norvig, "How to Write a Spelling Corrector", http://norvig.com/spell-correct.html |
| 1710 | |
| 1711 | class Spelling(lazydict): |
| 1712 | |
| 1713 | ALPHA = "abcdefghijklmnopqrstuvwxyz" |
| 1714 | |
| 1715 | def __init__(self, path=""): |
| 1716 | self._path = path |
| 1717 | |
| 1718 | def load(self): |
| 1719 | for x in _read(self._path): |
| 1720 | x = x.split() |
| 1721 | dict.__setitem__(self, x[0], int(x[1])) |
| 1722 | |
| 1723 | @property |
| 1724 | def path(self): |
| 1725 | return self._path |
| 1726 | |
| 1727 | @property |
| 1728 | def language(self): |
| 1729 | return self._language |
| 1730 | |
| 1731 | @classmethod |
| 1732 | def train(self, s, path="spelling.txt"): |
| 1733 | """ Counts the words in the given string and saves the probabilities at the given path. |
| 1734 | This can be used to generate a new model for the Spelling() constructor. |
| 1735 | """ |
| 1736 | model = {} |
| 1737 | for w in re.findall("[a-z]+", s.lower()): |
| 1738 | model[w] = w in model and model[w] + 1 or 1 |
| 1739 | model = ("%s %s" % (k, v) for k, v in sorted(model.items())) |
| 1740 | model = "\n".join(model) |
| 1741 | f = open(path, "w") |
| 1742 | f.write(model) |
| 1743 | f.close() |
| 1744 | |
| 1745 | def _edit1(self, w): |
| 1746 | """ Returns a set of words with edit distance 1 from the given word. |
| 1747 | """ |
| 1748 | # Of all spelling errors, 80% is covered by edit distance 1. |
| 1749 | # Edit distance 1 = one character deleted, swapped, replaced or inserted. |
| 1750 | split = [(w[:i], w[i:]) for i in range(len(w) + 1)] |
| 1751 | delete, transpose, replace, insert = ( |
| 1752 | [a + b[1:] for a, b in split if b], |
| 1753 | [a + b[1] + b[0] + b[2:] for a, b in split if len(b) > 1], |
| 1754 | [a + c + b[1:] for a, b in split for c in Spelling.ALPHA if b], |
| 1755 | [a + c + b[0:] for a, b in split for c in Spelling.ALPHA] |
| 1756 | ) |
| 1757 | return set(delete + transpose + replace + insert) |
| 1758 | |
| 1759 | def _edit2(self, w): |
| 1760 | """ Returns a set of words with edit distance 2 from the given word |
| 1761 | """ |
| 1762 | # Of all spelling errors, 99% is covered by edit distance 2. |
| 1763 | # Only keep candidates that are actually known words (20% speedup). |
| 1764 | return set(e2 for e1 in self._edit1(w) for e2 in self._edit1(e1) if e2 in self) |
| 1765 | |
| 1766 | def _known(self, words=[]): |
| 1767 | """ Returns the given list of words filtered by known words. |
| 1768 | """ |
no outgoing calls
no test coverage detected
searching dependent graphs…