Transposition ciphers working
[cipher-tools.git] / cipher.py
index 6ef01c325d81a7055760d924c400f86b8b718340..d2619029de591af1d07e5f85160e187629332751 100644 (file)
--- a/cipher.py
+++ b/cipher.py
@@ -2,8 +2,7 @@ import string
 import collections
 import logging
 from itertools import zip_longest, cycle, chain
-from counts import *
-
+from language_models import *
 
 logger = logging.getLogger(__name__)
 logger.addHandler(logging.FileHandler('cipher.log'))
@@ -12,45 +11,12 @@ logger.setLevel(logging.WARNING)
 #logger.setLevel(logging.DEBUG)
 
 
-english_counts = collections.defaultdict(int)
-with open('count_1l.txt', 'r') as f:
-    for line in f:
-        (letter, count) = line.split("\t")
-        english_counts[letter] = int(count)
-normalised_english_counts = norms.normalise(english_counts)
-
-choices, weights = zip(*weighted_choices)
-cumdist = list(itertools.accumulate(weights))
-x = random.random() * cumdist[-1]
-choices[bisect.bisect(cumdist, x)]
-
-
-modular_division_table = [[0]*26 for x in range(26)]
+modular_division_table = [[0]*26 for _ in range(26)]
 for a in range(26):
     for b in range(26):
         c = (a * b) % 26
         modular_division_table[b][c] = a
 
-def letters(text):
-    """Remove all non-alphabetic characters from a text
-    >>> letters('The Quick')
-    'TheQuick'
-    >>> letters('The Quick BROWN fox jumped! over... the (9lazy) DOG')
-    'TheQuickBROWNfoxjumpedoverthelazyDOG'
-    """
-    return ''.join([c for c in text if c in string.ascii_letters])
-
-def sanitise(text):
-    """Remove all non-alphabetic characters and convert the text to lowercase
-    
-    >>> sanitise('The Quick')
-    'thequick'
-    >>> sanitise('The Quick BROWN fox jumped! over... the (9lazy) DOG')
-    'thequickbrownfoxjumpedoverthelazydog'
-    """
-    # sanitised = [c.lower() for c in text if c in string.ascii_letters]
-    # return ''.join(sanitised)
-    return letters(text).lower()
 
 def ngrams(text, n):
     """Returns all n-grams of a text
@@ -439,20 +405,43 @@ def column_transposition_encipher(message, keyword, fillvalue=' ',
     """Enciphers using the column transposition cipher.
     Message is padded to allow all rows to be the same length.
 
-    >>> column_transposition_encipher('hellothere', 'clever')
+    >>> column_transposition_encipher('hellothere', 'abcdef', fillcolumnwise=True)
+    'hlohr eltee '
+    >>> column_transposition_encipher('hellothere', 'abcdef', fillcolumnwise=True, emptycolumnwise=True)
+    'hellothere  '
+    >>> column_transposition_encipher('hellothere', 'abcdef')
+    'hellothere  '
+    >>> column_transposition_encipher('hellothere', 'abcde')
+    'hellothere'
+    >>> column_transposition_encipher('hellothere', 'abcde', fillcolumnwise=True, emptycolumnwise=True)
+    'hellothere'
+    >>> column_transposition_encipher('hellothere', 'abcde', fillcolumnwise=True, emptycolumnwise=False)
+    'hlohreltee'
+    >>> column_transposition_encipher('hellothere', 'abcde', fillcolumnwise=False, emptycolumnwise=True)
+    'htehlelroe'
+    >>> column_transposition_encipher('hellothere', 'abcde', fillcolumnwise=False, emptycolumnwise=False)
+    'hellothere'
+    >>> column_transposition_encipher('hellothere', 'clever', fillcolumnwise=True, emptycolumnwise=True)
+    'heotllrehe'
+    >>> column_transposition_encipher('hellothere', 'clever', fillcolumnwise=True, emptycolumnwise=False)
+    'holrhetlee'
+    >>> column_transposition_encipher('hellothere', 'clever', fillcolumnwise=False, emptycolumnwise=True)
+    'htleehoelr'
+    >>> column_transposition_encipher('hellothere', 'clever', fillcolumnwise=False, emptycolumnwise=False)
     'hleolteher'
+    >>> column_transposition_encipher('hellothere', 'cleverly')
+    'hleolthre e '
     >>> column_transposition_encipher('hellothere', 'cleverly', fillvalue='!')
     'hleolthre!e!'
-    >>> column_transposition_encipher('hellothere', 'clever', columnwise=True)
-    'htleehoelr'
+    >>> column_transposition_encipher('hellothere', 'cleverly', fillvalue=lambda: '*')
+    'hleolthre*e*'
     """
     transpositions = transpositions_of(keyword)
     message += pad(len(message), len(transpositions), fillvalue)
     if fillcolumnwise:
-        rows = every_nth(message, len(transpositions))
+        rows = every_nth(message, len(message) // len(transpositions))
     else:
-        rows = chunks(mesage, len(transpositions))
-    columns = every_nth(message, len(transpositions), fillvalue=fillvalue)
+        rows = chunks(message, len(transpositions))
     transposed = [transpose(r, transpositions) for r in rows]
     if emptycolumnwise:
         return combine_every_nth(transposed)
@@ -460,24 +449,46 @@ def column_transposition_encipher(message, keyword, fillvalue=' ',
         return ''.join(chain(*transposed))
 
 def column_transposition_decipher(message, keyword, fillvalue=' ', 
-      columnwise=False):
+      fillcolumnwise=False,
+      emptycolumnwise=False):
     """Deciphers using the column transposition cipher.
     Message is padded to allow all rows to be the same length.
 
-    >>> column_transposition_decipher('hleolteher', 'clever')
+    >>> column_transposition_decipher('hellothere', 'abcde', fillcolumnwise=True, emptycolumnwise=True)
+    'hellothere'
+    >>> column_transposition_decipher('hlohreltee', 'abcde', fillcolumnwise=True, emptycolumnwise=False)
+    'hellothere'
+    >>> column_transposition_decipher('htehlelroe', 'abcde', fillcolumnwise=False, emptycolumnwise=True)
+    'hellothere'
+    >>> column_transposition_decipher('hellothere', 'abcde', fillcolumnwise=False, emptycolumnwise=False)
     'hellothere'
-    >>> column_transposition_decipher('hleolthre!e!', 'cleverly', fillvalue='?')
-    'hellothere!!'
-    >>> column_transposition_decipher('htleehoelr', 'clever', columnwise=True)
+    >>> column_transposition_decipher('heotllrehe', 'clever', fillcolumnwise=True, emptycolumnwise=True)
+    'hellothere'
+    >>> column_transposition_decipher('holrhetlee', 'clever', fillcolumnwise=True, emptycolumnwise=False)
+    'hellothere'
+    >>> column_transposition_decipher('htleehoelr', 'clever', fillcolumnwise=False, emptycolumnwise=True)
+    'hellothere'
+    >>> column_transposition_decipher('hleolteher', 'clever', fillcolumnwise=False, emptycolumnwise=False)
     'hellothere'
     """
+    # >>> column_transposition_decipher('hleolteher', 'clever')
+    # 'hellothere'
+    # >>> column_transposition_decipher('hleolthre!e!', 'cleverly', fillvalue='?')
+    # 'hellothere!!'
+    # >>> column_transposition_decipher('htleehoelr', 'clever', columnwise=True)
+    # 'hellothere'
+    # """
     transpositions = transpositions_of(keyword)
-    if columnwise:
-        columns = chunks(message, int(len(message) / len(transpositions)))
+    message += pad(len(message), len(transpositions), '*')
+    if emptycolumnwise:
+        rows = every_nth(message, len(message) // len(transpositions))
+    else:
+        rows = chunks(message, len(transpositions))
+    untransposed = [untranspose(r, transpositions) for r in rows]
+    if fillcolumnwise:
+        return combine_every_nth(untransposed)
     else:
-        columns = every_nth(message, len(transpositions), fillvalue=fillvalue)
-    untransposed_columns = untranspose(columns, transpositions)
-    return combine_every_nth(untransposed_columns)
+        return ''.join(chain(*untransposed))
 
 
 def vigenere_encipher(message, keyword):