mirror of
https://github.com/TheAlgorithms/Python.git
synced 2025-02-17 06:48:09 +00:00
Upgrades to caesar_cipher.py (#1958)
* Added more flexibility to functions, decreased amount of repeating code * Added docstrings * Updated input functions * Added doctests * removed test piece of code * black . * Updated caesar cipher standard alphabet to fit python 3.8 * Update and rename sleepsort.py to sleep_sort.py * Or 4 Co-authored-by: Christian Clauss <cclauss@me.com>
This commit is contained in:
parent
c18c677a38
commit
369562a1e8
|
@ -1,63 +1,250 @@
|
||||||
def encrypt(input_string: str, key: int) -> str:
|
from string import ascii_letters
|
||||||
|
|
||||||
|
|
||||||
|
def encrypt(input_string: str, key: int, alphabet=None) -> str:
|
||||||
|
"""
|
||||||
|
encrypt
|
||||||
|
=======
|
||||||
|
Encodes a given string with the caesar cipher and returns the encoded
|
||||||
|
message
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
-----------
|
||||||
|
* input_string: the plain-text that needs to be encoded
|
||||||
|
* key: the number of letters to shift the message by
|
||||||
|
|
||||||
|
Optional:
|
||||||
|
* alphabet (None): the alphabet used to encode the cipher, if not
|
||||||
|
specified, the standard english alphabet with upper and lowercase
|
||||||
|
letters is used
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
* A string containing the encoded cipher-text
|
||||||
|
|
||||||
|
More on the caesar cipher
|
||||||
|
=========================
|
||||||
|
The caesar cipher is named after Julius Caesar who used it when sending
|
||||||
|
secret military messages to his troops. This is a simple substitution cipher
|
||||||
|
where very character in the plain-text is shifted by a certain number known
|
||||||
|
as the "key" or "shift".
|
||||||
|
|
||||||
|
Example:
|
||||||
|
Say we have the following message:
|
||||||
|
"Hello, captain"
|
||||||
|
|
||||||
|
And our alphabet is made up of lower and uppercase letters:
|
||||||
|
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||||
|
|
||||||
|
And our shift is "2"
|
||||||
|
|
||||||
|
We can then encode the message, one letter at a time. "H" would become "J",
|
||||||
|
since "J" is two letters away, and so on. If the shift is ever two large, or
|
||||||
|
our letter is at the end of the alphabet, we just start at the beginning
|
||||||
|
("Z" would shift to "a" then "b" and so on).
|
||||||
|
|
||||||
|
Our final message would be "Jgnnq, ecrvckp"
|
||||||
|
|
||||||
|
Further reading
|
||||||
|
===============
|
||||||
|
* https://en.m.wikipedia.org/wiki/Caesar_cipher
|
||||||
|
|
||||||
|
Doctests
|
||||||
|
========
|
||||||
|
>>> encrypt('The quick brown fox jumps over the lazy dog', 8)
|
||||||
|
'bpm yCqks jzwEv nwF rCuxA wDmz Bpm tiHG lwo'
|
||||||
|
|
||||||
|
>>> encrypt('A very large key', 8000)
|
||||||
|
's nWjq dSjYW cWq'
|
||||||
|
|
||||||
|
>>> encrypt('a lowercase alphabet', 5, 'abcdefghijklmnopqrstuvwxyz')
|
||||||
|
'f qtbjwhfxj fqumfgjy'
|
||||||
|
"""
|
||||||
|
# Set default alphabet to lower and upper case english chars
|
||||||
|
alpha = alphabet or ascii_letters
|
||||||
|
|
||||||
|
# The final result string
|
||||||
result = ""
|
result = ""
|
||||||
for x in input_string:
|
|
||||||
if not x.isalpha():
|
for character in input_string:
|
||||||
result += x
|
if character not in alpha:
|
||||||
elif x.isupper():
|
# Append without encryption if character is not in the alphabet
|
||||||
result += chr((ord(x) + key - 65) % 26 + 65)
|
result += character
|
||||||
elif x.islower():
|
else:
|
||||||
result += chr((ord(x) + key - 97) % 26 + 97)
|
# Get the index of the new key and make sure it isn't too large
|
||||||
|
new_key = (alpha.index(character) + key) % len(alpha)
|
||||||
|
|
||||||
|
# Append the encoded character to the alphabet
|
||||||
|
result += alpha[new_key]
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
def decrypt(input_string: str, key: int) -> str:
|
def decrypt(input_string: str, key: int, alphabet=None) -> str:
|
||||||
result = ""
|
"""
|
||||||
for x in input_string:
|
decrypt
|
||||||
if not x.isalpha():
|
=======
|
||||||
result += x
|
Decodes a given string of cipher-text and returns the decoded plain-text
|
||||||
elif x.isupper():
|
|
||||||
result += chr((ord(x) - key - 65) % 26 + 65)
|
Parameters:
|
||||||
elif x.islower():
|
-----------
|
||||||
result += chr((ord(x) - key - 97) % 26 + 97)
|
* input_string: the cipher-text that needs to be decoded
|
||||||
return result
|
* key: the number of letters to shift the message backwards by to decode
|
||||||
|
|
||||||
|
Optional:
|
||||||
|
* alphabet (None): the alphabet used to decode the cipher, if not
|
||||||
|
specified, the standard english alphabet with upper and lowercase
|
||||||
|
letters is used
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
* A string containing the decoded plain-text
|
||||||
|
|
||||||
|
More on the caesar cipher
|
||||||
|
=========================
|
||||||
|
The caesar cipher is named after Julius Caesar who used it when sending
|
||||||
|
secret military messages to his troops. This is a simple substitution cipher
|
||||||
|
where very character in the plain-text is shifted by a certain number known
|
||||||
|
as the "key" or "shift". Please keep in mind, here we will be focused on
|
||||||
|
decryption.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
Say we have the following cipher-text:
|
||||||
|
"Jgnnq, ecrvckp"
|
||||||
|
|
||||||
|
And our alphabet is made up of lower and uppercase letters:
|
||||||
|
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||||
|
|
||||||
|
And our shift is "2"
|
||||||
|
|
||||||
|
To decode the message, we would do the same thing as encoding, but in
|
||||||
|
reverse. The first letter, "J" would become "H" (remember: we are decoding)
|
||||||
|
because "H" is two letters in reverse (to the left) of "J". We would
|
||||||
|
continue doing this. A letter like "a" would shift back to the end of
|
||||||
|
the alphabet, and would become "Z" or "Y" and so on.
|
||||||
|
|
||||||
|
Our final message would be "Hello, captain"
|
||||||
|
|
||||||
|
Further reading
|
||||||
|
===============
|
||||||
|
* https://en.m.wikipedia.org/wiki/Caesar_cipher
|
||||||
|
|
||||||
|
Doctests
|
||||||
|
========
|
||||||
|
>>> decrypt('bpm yCqks jzwEv nwF rCuxA wDmz Bpm tiHG lwo', 8)
|
||||||
|
'The quick brown fox jumps over the lazy dog'
|
||||||
|
|
||||||
|
>>> decrypt('s nWjq dSjYW cWq', 8000)
|
||||||
|
'A very large key'
|
||||||
|
|
||||||
|
>>> decrypt('f qtbjwhfxj fqumfgjy', 5, 'abcdefghijklmnopqrstuvwxyz')
|
||||||
|
'a lowercase alphabet'
|
||||||
|
"""
|
||||||
|
# Turn on decode mode by making the key negative
|
||||||
|
key *= -1
|
||||||
|
|
||||||
|
return encrypt(input_string, key, alphabet)
|
||||||
|
|
||||||
|
|
||||||
def brute_force(input_string: str) -> None:
|
def brute_force(input_string: str, alphabet=None) -> dict:
|
||||||
|
"""
|
||||||
|
brute_force
|
||||||
|
===========
|
||||||
|
Returns all the possible combinations of keys and the decoded strings in the
|
||||||
|
form of a dictionary
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
-----------
|
||||||
|
* input_string: the cipher-text that needs to be used during brute-force
|
||||||
|
|
||||||
|
Optional:
|
||||||
|
* alphabet: (None): the alphabet used to decode the cipher, if not
|
||||||
|
specified, the standard english alphabet with upper and lowercase
|
||||||
|
letters is used
|
||||||
|
|
||||||
|
More about brute force
|
||||||
|
======================
|
||||||
|
Brute force is when a person intercepts a message or password, not knowing
|
||||||
|
the key and tries every single combination. This is easy with the caesar
|
||||||
|
cipher since there are only all the letters in the alphabet. The more
|
||||||
|
complex the cipher, the larger amount of time it will take to do brute force
|
||||||
|
|
||||||
|
Ex:
|
||||||
|
Say we have a 5 letter alphabet (abcde), for simplicity and we intercepted the
|
||||||
|
following message:
|
||||||
|
|
||||||
|
"dbc"
|
||||||
|
|
||||||
|
we could then just write out every combination:
|
||||||
|
ecd... and so on, until we reach a combination that makes sense:
|
||||||
|
"cab"
|
||||||
|
|
||||||
|
Further reading
|
||||||
|
===============
|
||||||
|
* https://en.wikipedia.org/wiki/Brute_force
|
||||||
|
|
||||||
|
Doctests
|
||||||
|
========
|
||||||
|
>>> brute_force("jFyuMy xIH'N vLONy zILwy Gy!")[20]
|
||||||
|
"Please don't brute force me!"
|
||||||
|
|
||||||
|
>>> brute_force(1)
|
||||||
|
Traceback (most recent call last):
|
||||||
|
TypeError: 'int' object is not iterable
|
||||||
|
"""
|
||||||
|
# Set default alphabet to lower and upper case english chars
|
||||||
|
alpha = alphabet or ascii_letters
|
||||||
|
|
||||||
|
# The key during testing (will increase)
|
||||||
key = 1
|
key = 1
|
||||||
|
|
||||||
|
# The encoded result
|
||||||
result = ""
|
result = ""
|
||||||
while key <= 94:
|
|
||||||
for x in input_string:
|
# To store data on all the combinations
|
||||||
indx = (ord(x) - key) % 256
|
brute_force_data = {}
|
||||||
if indx < 32:
|
|
||||||
indx = indx + 95
|
# Cycle through each combination
|
||||||
result = result + chr(indx)
|
while key <= len(alpha):
|
||||||
print(f"Key: {key}\t| Message: {result}")
|
# Decrypt the message
|
||||||
|
result = decrypt(input_string, key, alpha)
|
||||||
|
|
||||||
|
# Update the data
|
||||||
|
brute_force_data[key] = result
|
||||||
|
|
||||||
|
# Reset result and increase the key
|
||||||
result = ""
|
result = ""
|
||||||
key += 1
|
key += 1
|
||||||
return None
|
|
||||||
|
return brute_force_data
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
while True:
|
while True:
|
||||||
print(f'{"-" * 10}\n Menu\n{"-" * 10}')
|
print(f'\n{"-" * 10}\n Menu\n{"-" * 10}')
|
||||||
print(*["1.Encrpyt", "2.Decrypt", "3.BruteForce", "4.Quit"], sep="\n")
|
print(*["1.Encrpyt", "2.Decrypt", "3.BruteForce", "4.Quit"], sep="\n")
|
||||||
choice = input("What would you like to do?: ")
|
|
||||||
if choice not in ["1", "2", "3", "4"]:
|
# get user input
|
||||||
|
choice = input("\nWhat would you like to do?: ").strip() or "4"
|
||||||
|
|
||||||
|
# run functions based on what the user chose
|
||||||
|
if choice not in ("1", "2", "3", "4"):
|
||||||
print("Invalid choice, please enter a valid choice")
|
print("Invalid choice, please enter a valid choice")
|
||||||
elif choice == "1":
|
elif choice == "1":
|
||||||
input_string = input("Please enter the string to be encrypted: ")
|
input_string = input("Please enter the string to be encrypted: ")
|
||||||
key = int(input("Please enter off-set between 0-25: "))
|
key = int(input("Please enter off-set: ").strip())
|
||||||
if key in range(1, 95):
|
|
||||||
print(encrypt(input_string.lower(), key))
|
print(encrypt(input_string, key))
|
||||||
elif choice == "2":
|
elif choice == "2":
|
||||||
input_string = input("Please enter the string to be decrypted: ")
|
input_string = input("Please enter the string to be decrypted: ")
|
||||||
key = int(input("Please enter off-set between 1-94: "))
|
key = int(input("Please enter off-set: ").strip())
|
||||||
if key in range(1, 95):
|
|
||||||
print(decrypt(input_string, key))
|
print(decrypt(input_string, key))
|
||||||
elif choice == "3":
|
elif choice == "3":
|
||||||
input_string = input("Please enter the string to be decrypted: ")
|
input_string = input("Please enter the string to be decrypted: ")
|
||||||
brute_force(input_string)
|
brute_force_data = brute_force(input_string)
|
||||||
main()
|
|
||||||
|
for key, value in brute_force_data.items():
|
||||||
|
print(f"Key: {key} | Message: {value}")
|
||||||
|
|
||||||
elif choice == "4":
|
elif choice == "4":
|
||||||
print("Goodbye.")
|
print("Goodbye.")
|
||||||
break
|
break
|
||||||
|
|
|
@ -84,6 +84,7 @@ def test_burkes(file_path: str = "digital_image_processing/image_data/lena_small
|
||||||
burkes.process()
|
burkes.process()
|
||||||
assert burkes.output_img.any()
|
assert burkes.output_img.any()
|
||||||
|
|
||||||
|
|
||||||
def test_nearest_neighbour(
|
def test_nearest_neighbour(
|
||||||
file_path: str = "digital_image_processing/image_data/lena_small.jpg",
|
file_path: str = "digital_image_processing/image_data/lena_small.jpg",
|
||||||
):
|
):
|
||||||
|
|
49
sorts/sleep_sort.py
Normal file
49
sorts/sleep_sort.py
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
"""
|
||||||
|
Sleep sort is probably the wierdest of all sorting functions with time-complexity of
|
||||||
|
O(max(input)+n) which is quite different from almost all other sorting techniques.
|
||||||
|
If the number of inputs is small then the complexity can be approximated to be
|
||||||
|
O(max(input)) which is a constant
|
||||||
|
|
||||||
|
If the number of inputs is large, the complexity is approximately O(n).
|
||||||
|
|
||||||
|
This function uses multithreading a kind of higher order programming and calls n
|
||||||
|
functions, each with a sleep time equal to its number. Hence each of function wakes
|
||||||
|
in sorted time.
|
||||||
|
|
||||||
|
This function is not stable for very large values.
|
||||||
|
|
||||||
|
https://rosettacode.org/wiki/Sorting_algorithms/Sleep_sort
|
||||||
|
"""
|
||||||
|
from threading import Timer
|
||||||
|
from time import sleep
|
||||||
|
from typing import List
|
||||||
|
|
||||||
|
|
||||||
|
def sleep_sort(values: List[int]) -> List[int]:
|
||||||
|
"""
|
||||||
|
Sort the list using sleepsort.
|
||||||
|
>>> sleep_sort([3, 2, 4, 7, 3, 6, 9, 1])
|
||||||
|
[1, 2, 3, 3, 4, 6, 7, 9]
|
||||||
|
>>> sleep_sort([3, 2, 1, 9, 8, 4, 2])
|
||||||
|
[1, 2, 2, 3, 4, 8, 9]
|
||||||
|
"""
|
||||||
|
sleep_sort.result = []
|
||||||
|
|
||||||
|
def append_to_result(x):
|
||||||
|
sleep_sort.result.append(x)
|
||||||
|
|
||||||
|
mx = values[0]
|
||||||
|
for value in values:
|
||||||
|
if mx < value:
|
||||||
|
mx = value
|
||||||
|
Timer(value, append_to_result, [value]).start()
|
||||||
|
sleep(mx + 1)
|
||||||
|
return sleep_sort.result
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
import doctest
|
||||||
|
|
||||||
|
doctest.testmod()
|
||||||
|
|
||||||
|
print(sleep_sort([3, 2, 4, 7, 3, 6, 9, 1]))
|
|
@ -1,48 +0,0 @@
|
||||||
"""Sleepsort is probably the wierdest of all sorting functions
|
|
||||||
with time-complexity of O(max(input)+n) which is
|
|
||||||
quite different from almost all other sorting techniques.
|
|
||||||
If the number of inputs is small then the complexity
|
|
||||||
can be approximated to be O(max(input)) which is a constant
|
|
||||||
|
|
||||||
If the number of inputs is large, the complexity is
|
|
||||||
approximately O(n).
|
|
||||||
|
|
||||||
This function uses multithreading a kind of higher order programming
|
|
||||||
and calls n functions, each with a sleep time equal to its number.
|
|
||||||
Hence each of the functions wake in sorted form.
|
|
||||||
|
|
||||||
This function is not stable for very large values.
|
|
||||||
|
|
||||||
https://rosettacode.org/wiki/Sorting_algorithms/Sleep_sort
|
|
||||||
"""
|
|
||||||
|
|
||||||
from time import sleep
|
|
||||||
from threading import Timer
|
|
||||||
from typing import List
|
|
||||||
|
|
||||||
|
|
||||||
def sleepsort(values: List[int]) -> List[int]:
|
|
||||||
"""
|
|
||||||
Sort the list using sleepsort.
|
|
||||||
>>> sleepsort([3, 2, 4, 7, 3, 6, 9, 1])
|
|
||||||
[1, 2, 3, 3, 4, 6, 7, 9]
|
|
||||||
>>> sleepsort([3, 2, 1, 9, 8, 4, 2])
|
|
||||||
[1, 2, 2, 3, 4, 8, 9]
|
|
||||||
"""
|
|
||||||
sleepsort.result = []
|
|
||||||
def append_to_result(x):
|
|
||||||
sleepsort.result.append(x)
|
|
||||||
mx = values[0]
|
|
||||||
for v in values:
|
|
||||||
if mx < v:
|
|
||||||
mx = v
|
|
||||||
Timer(v, append_to_result, [v]).start()
|
|
||||||
sleep(mx+1)
|
|
||||||
return sleepsort.result
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
import doctest
|
|
||||||
doctest.testmod()
|
|
||||||
x = [3, 2, 4, 7, 3, 6, 9, 1]
|
|
||||||
sorted_x = sleepsort(x)
|
|
||||||
print(sorted_x)
|
|
Loading…
Reference in New Issue
Block a user