Skip to content

Instantly share code, notes, and snippets.

@sistemd
Created July 30, 2017 16:31
Show Gist options
  • Save sistemd/0315410bda7ff09b3afab86e5400fd2a to your computer and use it in GitHub Desktop.
Save sistemd/0315410bda7ff09b3afab86e5400fd2a to your computer and use it in GitHub Desktop.
The master cryptanalyst
#!/usr/bin/env python3
from typing import TypeVar, Iterator, List, Dict
import enum
import re
import colorama
colorama.init()
class NotAnUppercaseLetter(Exception):
pass
class CharacterEncrypted(Exception):
pass
class AlreadyHasSubstitution(Exception):
pass
class CharacterSubstitutions:
def __init__(self, text: str) -> None:
self.__character_substitutions: Dict[str, str] = {}
for char in text.upper():
if not is_uppercase_letter(char):
self.__character_substitutions[char] = char
def substitution_for_character(self, char: str) -> str:
return self.__character_substitutions[char.upper()]
def character_has_substitution(self, char: str) -> bool:
char = char.upper()
return char in self.__character_substitutions
def create_substitution(self, old: str, new: str):
old = old.upper()
new = new.upper()
if self.character_has_substitution(old):
raise AlreadyHasSubstitution
self.__character_substitutions[old] = new
class Cipher:
def __init__(self, text: str) -> None:
self.__text = text.upper()
self.__character_substitutions = CharacterSubstitutions(text)
def decrypt_character(self, old: str, new: str):
self.__character_substitutions.create_substitution(old, new)
def decrypt_string(self, old: str, new: str) -> None:
for old_char, new_char in zip(old, new):
self.decrypt_character(old_char, new_char)
def most_common_word_of_length(self, length: int) -> str:
return most_common_word_of_length(self.__text, length)
def fancy_print(self) -> None:
print(self.__fancy_string())
def __fancy_string(self) -> str:
result = ''
for char in self.__text:
if self.__character_substitutions.character_has_substitution(char):
result += self.__character_substitutions.substitution_for_character(char)
else:
result += colorama.Fore.LIGHTRED_EX + char + colorama.Fore.WHITE
return result
def is_uppercase_letter(s: str) -> bool:
"""
>>> is_uppercase_letter('a')
False
>>> is_uppercase_letter('B')
True
>>> is_uppercase_letter('3')
False
>>> is_uppercase_letter('string')
False
"""
match = re.match(r'[A-Z]', s)
return match is not None and len(match.group()) == len(s)
def all_indexes(s: str, sub: str) -> Iterator[int]:
"""
>>> list(all_indexes('Hello world', 'o'))
[4, 7]
>>> list(all_indexes('', 'example'))
[]
>>> list(all_indexes('example', ''))
[]
>>> list(all_indexes('abracadabra', 'ab'))
[0, 7]
"""
if sub == '':
return
i = -1
while True:
i = s.find(sub, i + 1)
if i == -1:
break
yield i
def most_common_word_of_length(s: str, length) -> str:
return most_common_element(list(words_of_length(s, length)))
def words(s: str) -> List[str]:
return s.split(' ')
def words_of_length(s: str, length: int) -> Iterator[str]:
yield from (word for word in words(s) if len(word) == length)
T = TypeVar('T')
class EmptyList(Exception):
pass
def most_common_element(l: List[T]) -> T:
if not l:
raise EmptyList
value_to_count = value_to_count_dict(l)
value, highest_count = max(value_to_count.items(), key=lambda value_and_count: value_and_count[1])
return value
def value_to_count_dict(l: List[T]) -> Dict[T, int]:
return {e: l.count(e) for e in l}
if __name__ == '__main__':
import doctest
doctest.testmod()
http://imgur.com/a/jxmFb
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment