3.5. Programming the Rail Fence Cipher#

Below is are two functions that successfully clean the text and implement the Rail Fence cipher for enciphering messages. These functions showcases many of the programming skills covered up to this point including:

  • functions

  • optional keyword arguments

  • loops

  • string slicing

  • conditional branches

  • docstrings

It does not include the code for:

  • deciphering 2 row rail fence messages

  • deciphering 3 row rail fence messages

  • enciphering or deciphering rail fence messages with 4 or more rows

def text_clean( text ):
    """
    Arguments:
        text (str): a string containing text
    Returns:
        (str): the input string with spaces, non letter characters removed.
               letters will be upper-case
    """
    LETTERS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
    text = text.upper()
    cleaned = ''
    for char in text:
        if char in LETTERS:
            cleaned += char
            
    return cleaned
def railfence(text, rows, encipher=True):
    """
    Example of Use:
        >>> railfence('samplemessage', 3)
        'SLSEAPEESGMMA'
    
    Arguments:
        text (str):  represents either plaintext or ciphertext
        rows (int):  integer that represents the number of rows
        
    Returns:
        (str): represents the output, either plaintext or ciphertext
        (str): an error message
    """
    
    text = text_clean( text )
    
    if rows == 2:
        if encipher == True:
            return text[::2].upper() + text[1::2].upper()
        else:
            return "this is where the 2 row decipher code will go"
    elif rows == 3:
        if encipher == True:
            return text[::4].upper() + text[1::2].upper() + text[2::4].upper()
        else:
            return "this is where the 3 row decipher code will go"
    else:
        return "number of rails not supported"

We can see the different ways that we can use this function below:

help( railfence )
Help on function railfence in module __main__:

railfence(text, rows, encipher=True)
    Example of Use:
        >>> railfence('samplemessage', 3)
        'SLSEAPEESGMMA'
    
    Arguments:
        text (str):  represents either plaintext or ciphertext
        rows (int):  integer that represents the number of rows
        
    Returns:
        (str): represents the output, either plaintext or ciphertext
        (str): an error message
print( railfence('samplemessage', 3) )
SLSEAPEESGMMA
print( railfence('samplemessage', 2) )
SMLMSAEAPEESG
print( railfence('samplemessage', 5) )
number of rails not supported
print( railfence('SMLMSAEAPEESG', 2, encipher=False) )
this is where the 2 row decipher code will go
print( railfence('SLSEAPEESGMMA', 3, encipher=False) )
this is where the 3 row decipher code will go

A helpful way to visualize how these two functions, text_clean and railfence work together, we can use the code visualization tool at Python Tutor to see the different step-by-step operations that take place. In the area below, you can resize each half of the example to see more or less of the code on the left or the diagrams on the right. Click on the next button will step through the code one line at a time. The slider allows you to move quicker through the code. The diagram on the right shows how objects are currently stored in the computer.

The functions text_clean and railfence are considered global objects, meaning that every other object in the notebook as access to them at all times. You can also see that certain variables, like LETTERS, cleaned, and char are local only to the text_clean function, and other like rows and encipher are local only to railfence as indicated by the box around each function in which they are contained. Other functions outside the box can’t access or alter them, unless specifically allowed access to the objects by using a return statement.

Stepping through the code line by line allows you to see how the for loop iterates over the LETTERS string one character at a time, and makes a decision on whether to move it to the cleaned string, or ignore it. Only the characters that are moved are returned back to the railfence function, and assigned to the local variable text.

The Python Tutor website is a great resource to see how your code is working and identify possible bugs in your code.