Encoded Strings

Encoded Strings

December 31, 2023
medium
String Manipulation, Cryptography Basics

Problem #

You are given a string encoded with a simple shift cipher where each letter is shifted by a certain number of places. Write an algorithm to decode this string given the number of places each letter is shifted.

Solution #

Here’s the Python code to decode a string that has been encoded using a simple shift cipher:

def decodeShiftCipher(text, shift):
    """
    Decode a string that was encoded using a simple shift cipher.

    Args:
    text (str): The encoded string.
    shift (int): The number of places each letter in the string was shifted.

    Returns:
    str: The decoded string.
    """
    decoded_text = ""

    for char in text:
        if char.isalpha():
            # Calculate shifted position
            shifted = ord(char) - shift

            # Wrap around the alphabet if necessary
            if char.islower():
                if shifted < ord('a'):
                    shifted += 26
            elif char.isupper():
                if shifted < ord('A'):
                    shifted += 26

            # Append the decoded character
            decoded_text += chr(shifted)
        else:
            # Non-alphabetic characters are added as they are
            decoded_text += char

    return decoded_text

# Example usage
encoded_text = "Ifmmp!Xpsme"
shift = 1
decoded_text = decodeShiftCipher(encoded_text, shift)
print(decoded_text)

In this code, the decodeShiftCipher function takes two parameters: the encoded text and the shift value. It iterates over each character in the input text, shifting alphabetic characters back by the specified shift amount and handling wrap-around at the beginning of the alphabet. Non-alphabetic characters remain unchanged. The function returns the decoded string.

The example demonstrates decoding the string "Ifmmp!Xpsme" with a shift of 1, resulting in the output "Hello!World".

The provided Python function decodeShiftCipher successfully decodes a string that was encoded using a simple shift cipher. In the example usage, the encoded text "Ifmmp!Xpsme" is decoded with a shift of 1, resulting in the decoded string "Hello!World".

Here’s how the code works:

  1. Function Definition: decodeShiftCipher(text, shift) takes two arguments: the encoded text and the shift value used in the cipher.

  2. Initialization: decoded_text = "" initializes an empty string to store the decoded text.

  3. Iterating Through the Text: The function iterates over each character in the text.

  4. Decoding Characters:

    • If the character is alphabetic (char.isalpha()), it calculates its original position before the shift.
    • The calculation shifted = ord(char) - shift adjusts the ASCII value of the character back by the shift amount.
    • It then checks if this adjustment crosses the beginning of the alphabet (either ‘a’ or ‘A’). If so, it wraps around by adding 26 (the number of letters in the alphabet).
    • decoded_text += chr(shifted) converts the adjusted ASCII value back to a character and appends it to decoded_text.
  5. Handling Non-Alphabetic Characters: Non-alphabetic characters are added to decoded_text without any change.

  6. Returning the Result: After processing all characters, the function returns the decoded text.

This function is useful for decoding messages that were encoded with a basic Caesar cipher, where each letter in the plaintext is shifted a certain number of places down or up the alphabet.

Solution Analysis #

The shifted += 26 part of the code is there to handle the wrap-around in the alphabet when decoding the ciphered text. Let me explain this with more detail:

In a shift cipher, each letter in the plaintext is shifted a certain number of places down or up the alphabet. For example, with a shift of 1, ‘A’ becomes ‘B’, ‘B’ becomes ‘C’, and so on. However, what happens when you reach the end of the alphabet, or in the case of decoding, the beginning? This is where wrap-around comes into play.

When decoding, you are shifting the letters back. If you subtract the shift value from a letter and it goes past ‘A’ (for uppercase) or ‘a’ (for lowercase), it needs to wrap around to the end of the alphabet. In ASCII, the character ‘A’ has a value of 65, and ‘a’ has a value of 97. If your shifting results in a value less than these, you’ve gone past the beginning of the alphabet.

Here’s an example to illustrate:

  • Suppose you have the letter ‘A’ and you are using a shift of 1. When you decode, you subtract 1 from ‘A’, which would give you a character before ‘A’, which doesn’t make sense in the context of the alphabet.
  • To handle this, when shifted < ord('A') (or shifted < ord('a') for lowercase), you add 26 (the total number of letters in the alphabet) to shifted.
  • So, ‘A’ (65) - 1 = 64, which is less than the ASCII value for ‘A’. By adding 26, it becomes 90, which corresponds to ‘Z’.

This way, the code ensures that the alphabet is treated as a continuous loop, and the shift correctly transitions from the start of the alphabet to the end, and vice versa.

Solution 2 #

def decode_shift_cipher(encoded_string, shift):
  """
  Decodes a string encoded with a simple shift cipher.

  Args:
    encoded_string: The string to decode.
    shift: The number of places each letter is shifted.

  Returns:
    The decoded string.
  """

  alphabet = "abcdefghijklmnopqrstuvwxyz"
  shifted_alphabet = alphabet[shift:] + alphabet[:shift]

  decoded_string = ""
  for char in encoded_string:
    if char.isalpha():
      if char.isupper():
        decoded_string += shifted_alphabet[ord(char) - ord("A")].upper()
      else:
        decoded_string += shifted_alphabet[ord(char) - ord("a")].lower()
    else:
      decoded_string += char

  return decoded_string

# Example usage
encoded_string = "Gdqkdb ekd vxqj!"
shift = 3
decoded_string = decode_shift_cipher(encoded_string, shift)
print(f"Decoded string: {decoded_string}")