Merge branch 'neil' of git.njae.me.uk:national-cipher-challenge into neil
[cipher-tools.git] / cipher.py
index 7d3ba78e4045082e394608620f1ac3c6b16733da..c2038458aee5416fbc66f53b5a3668a42165381a 100644 (file)
--- a/cipher.py
+++ b/cipher.py
@@ -43,6 +43,14 @@ for a 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
@@ -52,8 +60,9 @@ def sanitise(text):
     >>> 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)
+    # 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
@@ -152,11 +161,14 @@ def frequencies(text):
      ('h', 2), ('i', 1), ('j', 1), ('k', 1), ('l', 1), ('m', 1), ('n', 1), 
      ('o', 4), ('p', 1), ('q', 1), ('r', 2), ('t', 2), ('u', 2), ('v', 1), 
      ('w', 1), ('x', 1), ('y', 1), ('z', 1)]
+    >>> frequencies('abcdefabcdef')['x']
+    0
     """
-    counts = collections.defaultdict(int)
-    for c in text: 
-        counts[c] += 1
-    return counts
+    #counts = collections.defaultdict(int)
+    #for c in text: 
+    #    counts[c] += 1
+    #return counts
+    return collections.Counter(c for c in text)
 letter_frequencies = frequencies
 
 def deduplicate(text):
@@ -424,10 +436,8 @@ def transpositions_of(keyword):
     >>> transpositions_of('clever')
     [0, 2, 1, 4, 3]
     """
-    transpositions = []
     key = deduplicate(keyword)
-    for l in sorted(key):
-        transpositions += [key.index(l)]
+    transpositions = [key.index(l) for l in sorted(key)]
     return transpositions
 
 def column_transposition_encipher(message, keyword):
@@ -435,19 +445,30 @@ def column_transposition_encipher(message, keyword):
     >>> column_transposition_encipher('hellothere', 'clever')
     'hleolteher'
     """
-    transpositions = transpositions_of(keyword)
-    columns = every_nth(message, len(transpositions), fillvalue=' ')
-    transposed_columns = transpose(columns, transpositions)
-    return combine_every_nth(transposed_columns)
+    return column_transposition_worker(message, keyword, encipher=True)
 
 def column_transposition_decipher(message, keyword):
     """
     >>> column_transposition_decipher('hleolteher', 'clever')
     'hellothere'
     """
+    return column_transposition_worker(message, keyword, encipher=False)
+
+def column_transposition_worker(message, keyword, encipher=True):
+    """
+    >>> column_transposition_worker('hellothere', 'clever')
+    'hleolteher'
+    >>> column_transposition_worker('hellothere', 'clever', encipher=True)
+    'hleolteher'
+    >>> column_transposition_worker('hleolteher', 'clever', encipher=False)
+    'hellothere'
+    """
     transpositions = transpositions_of(keyword)
     columns = every_nth(message, len(transpositions), fillvalue=' ')
-    transposed_columns = untranspose(columns, transpositions)
+    if encipher:
+        transposed_columns = transpose(columns, transpositions)
+    else:
+        transposed_columns = untranspose(columns, transpositions)
     return combine_every_nth(transposed_columns)