disclaimer im new to python
i need to split a string input send if to a function that substitutes a character in the string with a different character (like a substitution cipher) but i just dont know how to go about this
print('Welcome to the encryption protocol for top secret governemt cover ups')
string=input('whats your message?')
def encrypt(string):
alpha = "abcdefghijklmnopqrstuvwyz"
sub_alpha = "pokmenliuytrwqazxcvsdfgbhn"
index=0
while index < len(string):
letter=string[index]
im not really sure what im doing im really bad at python, this has had me stumped for 3 days now ive reviewed my course material and tried videos on youtube im probably just really really dumb
I think the key piece of knowledge you're missing is that strings are iterable. So you can do things like:
for c in "FOO":
print(c)
# prints "F\nO\nO\n"
And you can find the index of a character within a string with str.index. So you can build up your cyphertext like this:
alpha = "abcdefghijklmnopqrstuvwyz "
cypher = "pokmenliuytrw qazxcvsdfgbhn"
plaintext = "some string"
cyphertext = ""
for c in plaintext:
char_index = alpha.index(c)
cyphertext += cypher[char_index]
You can also iterate over things inline - this is called a comprehension. So to transform your string you can do this instead of using the for loop:
cyphertext = "".join(cypher[alpha.index(c)] for c in plaintext)
The example above uses the str.join function to concatenate each character of cyphertext.
Here is a solution that asks the question and then iterates through each letter, finding the index in the alpha key, and replacing it with the sub_alpha key equivalent.
Note this example also checks if it should be lowercase or uppercase.
EDIT: if the input character does not have a valid cipher, it doesn't get altered.
EDIT 2: expanded answer to convert both forwards and backwards.
alpha = "abcdefghijklmnopqrstuvwyz"
sub_alpha = "pokmenliuytrwqazxcvsdfgbhn"
def encrypt(in_char):
is_lower_case = in_char.islower()
index = alpha.find(in_char.lower())
if index < 0:
return in_char
elif is_lower_case:
return sub_alpha[index]
else:
return sub_alpha[index].upper()
def decrypt(in_char):
is_lower_case = in_char.islower()
index = sub_alpha.find(in_char.lower())
if index < 0:
return in_char
elif is_lower_case:
return alpha[index]
else:
return alpha[index].upper()
print('Welcome to the encryption protocol for top secret governemt cover ups')
input_str=input('whats your message? ')
output_str=""
for letter in input_str:
output_str += encrypt(letter)
print("Encrypted: ")
print(output_str)
input_str=""
for letter in output_str:
input_str+= decrypt(letter)
print("Decrypted: ")
print(input_str)
Related
I am trying to create a function which is able to detect when two letters back to back are duplicates, for example the ls in "hello", and split the duplicate letters with the letter "x". Here is my code:
plaintext = input("Enter plaintext here: ")
plaintext = plaintext.lower() # makes plaintext lowercase
plaintext = plaintext.replace(" ", "") # removes all spaces
# this separates all duplicate letters
i = 0 # sets i to 0
for letter in plaintext:
if plaintext[-1] == plaintext[-2]: # if the last letter is the same as the second to last
plaintext = plaintext[:-1] + "x" + plaintext[-1:] # separate them with an x
elif plaintext[i] == plaintext [i+1]: # if one letter is the same as the next letter
# the line above makes an error
plaintext = plaintext[:i+1] + "x" + plaintext[i+1:] #separate them with an x
i += 1
else:
i += 1
This code works when I enter hello there as the input; I receive helxlothere. However, when I test another input, such as heythere, IndexError: string index out of range shows up for elif line (line 12). How can I make this code work for all inputs?
You can use regex to achieve this.
For both approaches, it will work for hello there hey there
The difference comes when more than two character repetition happens.
approach 1
import re
string='hello there'
# find Any repeated character and add x in between them
answer = re.sub(r'(.)\1{1}', r'\1x\1', string)
print(answer)
Here for hellllo there text, you will get output helxllxlo there
approach 2
alternatively, you can use this method.
s="hello there"
for match in re.finditer(r"(.)\1+", s):
old=s[match.start():match.end()]
s=s.replace(old,'x'.join(old))
print(s)
here for hellllo there text, you will get output helxlxlxlo there as output.
I think the second approach will be more appropriate.
The IndexError is caused by the fact that you are looking at plaintext[i+1]. As you can see in the word heythere, there are no letters which match back to back, and therefore the code continues until it hits the end, and so you get an IndexError because there is no element i+1.
You can fix this by using this code instead:
plaintext = input("Enter plaintext here: ")
plaintext = plaintext.lower() # makes plaintext lowercase
plaintext = plaintext.replace(" ", "") # removes all spaces
# this separates all duplicate letters
i = 0 # sets i to 0
for letter in plaintext:
if plaintext[-1] == plaintext[-2]: # if the last letter is the same as the second to last
plaintext = plaintext[:-1] + "x" + plaintext[-1:] # separate them with an x
try:
elif plaintext[i] == plaintext [i+1]: # if one letter is the same as the next letter
# the line above makes an error
plaintext = plaintext[:i+1] + "x" + plaintext[i+1:] #separate them with an x
i += 1
else:
i += 1
except IndexError:
pass
This code should stop your code from crashing in the elif statement, while also completing properly.
Hope this helps, have a nice day!
You are receiving the IndexError because during iterating, when the loop reaches the last letter,
elif plaintext[i] == plaintext [i+1]:
this line checks for the letter after the last letter, which does not exist, which causes the program to run into IndexError.
You have to check till the second last letter, for it to work properly.
A simple and easier way to arrive at the same output with a bit easier logic.
Logic
Create a new string and insert all letters which are in the old string, plaintext, to the new string, newPlainText, and check only for one condition that is whether the last letter is same as current or not and if yes then also insert letter 'x' into the newPlainText and that's it!
plaintext = input("Enter plaintext here: ")
plaintext = plaintext.lower() # makes plaintext lowercase
plaintext = plaintext.replace(" ", "") # removes all spaces
# this separates all duplicate letters
newPlainText = plaintext[0] # copy the first letter of plaintext to the new string which will handle the duplicates and insert `x` between them
i = 1 # sets i to 1
while i < len(plaintext):
if plaintext[i] == plaintext[i-1]: # we check that if prev and current letters are same then also append x to the new string
newPlainText += "x"
newPlainText += plaintext[i] # we insert the required current letter to the new string in each iteration
i += 1
print(newPlainText)
I have been playing with Python and came across a task from MIT, which is to create coded message (Julius Cesar code where for example you change ABCD letters in message to CDEF). This is what I came up with:
Phrase = input('Type message to encrypt: ')
shiftValue = int(input('Enter shift value: '))
listPhrase = list(Phrase)
listLenght = len(listPhrase)
ascii = []
for ch in listPhrase:
ascii.append(ord(ch))
print (ascii)
asciiCoded = []
for i in ascii:
asciiCoded.append(i+shiftValue)
print (asciiCoded)
phraseCoded = []
for i in asciiCoded:
phraseCoded.append(chr(i))
print (phraseCoded)
stringCoded = ''.join(phraseCoded)
print (stringCoded)
The code works but I have to implement not shifting the ascii value of spaces and special signs in message.
So my idea is to select values in list in range of range(65,90) and range(97,122) and change them while I do not change any others. But how do I do that?
If you want to use that gigantic code :) to do something as simple as that, then you keep a check like so:
asciiCoded = []
for i in ascii:
if 65 <= i <= 90 or 97 <= i <= 122: # only letters get changed
asciiCoded.append(i+shiftValue)
else:
asciiCoded.append(i)
But you know what, python can do the whole of that in a single line, using list comprehension. Watch this:
Phrase = input('Type message to encrypt: ')
shiftValue = int(input('Enter shift value: '))
# encoding to cypher, in single line
stringCoded = ''.join(chr(ord(c)+shiftValue) if c.isalpha() else c for c in Phrase)
print(stringCoded)
A little explanation: the list comprehension boils down to this for loop, which is easier to comprehend. Caught something? :)
temp_list = []
for c in Phrase:
if c.isalpha():
# shift if the c is alphabet
temp_list.append(chr(ord(c)+shiftValue))
else:
# no shift if c is no alphabet
temp_list.append(c)
# join the list to form a string
stringCoded = ''.join(temp_list)
Much easier it is to use the maketrans method from the string module:
>>import string
>>
>>caesar = string.maketrans('ABCD', 'CDEF')
>>
>>s = 'CAD BA'
>>
>>print s
>>print s.translate(caesar)
CAD BA
ECF DC
EDIT: This was for Python 2.7
With 3.5 just do
caesar = str.maketrans('ABCD', 'CDEF')
And an easy function to return a mapping.
>>> def encrypt(shift):
... alphabet = string.ascii_uppercase
... move = (len(alphabet) + shift) % len(alphabet)
... map_to = alphabet[move:] + alphabet[:move]
... return str.maketrans(alphabet, map_to)
>>> "ABC".translate(encrypt(4))
'EFG'
This function uses modulo addition to construct the encrypted caesar string.
asciiCoded = []
final_ascii = ""
for i in ascii:
final_ascii = i+shiftValue #add shiftValue to ascii value of character
if final_ascii in range(65,91) or final_ascii in range(97,123): #Condition to skip the special characters
asciiCoded.append(final_ascii)
else:
asciiCoded.append(i)
print (asciiCoded)
This question already has answers here:
Repeat string to certain length
(15 answers)
Closed 5 months ago.
In school we are currently using python to create a Caeser Cipher, and a Keyword Cipher. I need help with certain parts of the Keyword cipher, mainly repeating a word to match the length of a string that has been entered, For example:
Entered String: Hello I am Jacob Key: bye Printed text: byebyebyebyeb
I'm okay at Python, but this is very hard for me. Currently this is as far as I got:
def repeat_to_length(key, Input):
return (key * ((ord(Input)/len(key))+1))[:ord(Input)]
Since It's a string I thought if I used ord It would turn it to a number, but I realised when using the ord command you can only have a single character, as I realised when I repeatedly got this error:
TypeError: ord() expected a character, but string of length 16 found
I found some code that did a keyword cipher, but I am not sure which part does the process I am trying to code:
def createVigenereSquare():
start = ord('a')
end = start + 26
index = start
sq = [''] * 256
for i in range(start, end):
row = [''] * 256
for j in range(start, end):
if index > (end - 1):
index = start
row[j] = chr(index)
index += 1
sq[i] = row
index = i + 1
return sq
def createKey(message, keyword):
n = 0
key = ""
for i in range(0, len(message)):
if n >= len(keyword):
n = 0
key += keyword[n]
n += 1
return key
def createCipherText(message, key):
vsquare = createVigenereSquare()
cipher = ""
for i in range(0, len(key)):
cipher += vsquare[ord(key[i])][ord(message[i])]
return cipher
message = str(input("Please input a message using lowercase letters: "))
keyword = str(input("Please input a single word with lowercase letters: "))
key = createKey(message, keyword)
ciphertext = createCipherText(message, key)
print ("Message: " + message)
print ("Keyword: " + keyword)
print ("Key: " + key)
print ("Ciphertext: " + ciphertext)
As I've said I'm only okay at Python, so I don't really understand all the code in the above code, and I really want to be able to write most of it myself.
This is my code so far:
def getMode():
while True:
print("Enter encrypt, e, decrypt or d")
mode = input('Do you want to encrypt the message or decrypt? ') #changes whether the code encrypts or decrypts message
if mode in 'encrypt e decrypt d ENCRYPT E DECRYPT D'.split(): #defines the various inputs that are valid
return mode
else:
print('Enter either "encrypt" or "e" or "decrypt" or "d".') #restarts this string of code if the input the user enters is invalid
Input = input('Enter your message: ')
key = input('Enter the one word key: ')
def repeat_to_length(key, Input):
return (key * ((ord(Input)/len(key))+1))[:ord(Input)]
encryptedKey = repeat_to_length(key, Input)
print(encryptedKey)
I know I've been pretty long winded but if anyone could provide any information on this topic, like explaining the code for the keyword cipher, or just answering my question, I would appreciate it!
AnimeDeamon
Another possibility is to repeat the key enough times to get a string at least as long as the message, and then just grab as many characters as you need from the beginning:
>>> message='Hello I am Jacob'
>>> key='bye'
>>> times=len(message)//len(key)+1
>>> print((times*key)[:len(message)])
byebyebyebyebyeb
We compute times by dividing the length of the message by the length of the string, but we have to add 1, because any remainder will be dropped. times*key is just key repeated times times. This may be longer than we want, so we just take the first len(message) characters.
A simple one-liner could be
''.join(key[i % len(key)] for i in range(len(message)))
What it does, inside out:
We iterate over the indices of the letters in the string message
For each index, we take the remainder after division with the key length (using the % operator) and get the corresponding letter from the key
A list of these letters is constructed (using list comprehension) and joined together to form a string (the join method of an empty string)
Example:
>>> message = "Hello I am Jacob"
>>> key = "bye"
>>> print ''.join(key[i % len(key)] for i in range(len(message)))
byebyebyebyebyeb
I'm trying to work on a basic python program that is to find a substring of a string in python but the challenge was I can't use built functions or slicing.
MAINSTRING = raw_input('Enter a string : ')
print 'You entered %s' %MAINSTRING
isSubString = raw_input('Enter the substring : ')
print 'You entered %s' %isSubString
if isSubString in MAINSTRING:
print isSubString + " is a substring of " + MAINSTRING
It works but I can't use in syntax which is the frustrating part. I also know to use the slicing method in python but my challenge was to break it to the basics.
Sorry for being so vague, but I just got a hint.
The complete code consist of two 'for' loops, one for the string and one for the substring
To avoid anything other than for loops and a function you could do it like this although I have no idea why. Also you will have to use in which is pointed out in the comments. If a letter in the mainstring matches the first letter in the substring then add it to the temp string t, then go to the next letters in each and see if they match. If the temp string equals the substring then it exists and it will return.
def substring(ss, s):
x = 0
t = ""
for i in range(len(s)):
if s[i] == ss[x]:
t += ss[x]
if t == ss:
return s
x+=1
else:
x = 0
t = ""
It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 10 years ago.
So, I need to input a scrambled alphabet, and then input a secret message using that alphabet. My program needs to unscramble the secret message. I have written this so far and am stuck. I was hoping someone could help me. What I tried so far is changing every index in the list to A-Z. My question is how do I use what I wrote for that and make it work for the secret message I input as well.
s = ()
alphabet = input("Please input the scrambled alphabet in order: ")
message = input("Now input the scrambled message: ")
alphabet.upper()
s = dict(alphabet)
num = 1
while num < 2:
s[0] = chr(65)
s[1] = chr(66)
s[2] = chr(67)
s[3] = chr(68)
s[4] = chr(69)
s[5] = chr(70)
s[6] = chr(71)
s[7] = chr(72)
s[8] = chr(73)
s[9] = chr(74)
s[10] = chr(75)
s[11] = chr(76)
s[12] = chr(77)
s[13] = chr(78)
s[14] = chr(79)
s[15] = chr(80)
s[16] = chr(81)
s[17] = chr(82)
s[18] = chr(83)
s[19] = chr(84)
s[20] = chr(85)
s[21] = chr(86)
s[22] = chr(87)
s[23] = chr(88)
s[24] = chr(89)
s[25] = chr(90)
num +=1
print (s)
for alpha in message.upper():
if alpha < "A" or alpha > "Z":
print(alpha,end="")
else:
print(s [ord(alpha) -65 ], end="")
First, creating the big dictionary s is entirely unnecessary. It literally does nothing: the line:
s [ord(alpha) -65 ]
Is turning a letter into a number, subtracting 65, and then putting it through a dictionary that adds 65 and turns it back into a number.
Secondly, the line alphabet.upper() doesn't actually change the alphabet, it just returns an uppercase version. You need to do
alphabet = alphabet.upper()
Now for the meaty part. What you meant to do was create a dictionary mapping letters in the code alphabet to letters in the real alphabet. The line dict(alphabet) doesn't do this. Instead, iterate through the characters in the string and assign each to the corresponding letter. You're on the right track using chr, but are going to way too much work. How about this:
s = {}
for i in range(26): # iterate from 0 to 25
s[alphabet[i]] = chr(65 + i)
since chr(65 + i) is the letter in the normal, ordered alphabet, and alphabet[i] is the scrambled one.
Once you have that dictionary, running through letter by letter and changing it should be easy (and it's left to you).
You could use the string translate() method:
import string
intab = 'abcdefghijklmnopqrstuvwxyz' # or string.ascii_lowercase
outtab = 'xyzabcdefghijklmnopqrstuvw'
tab = string.maketrans(intab, outtab)
s = raw_input('Type some text: ').lower()
print s.translate(tab)
maketrans() creates a table with both alphabets, and translate() just replace each character of the string by its pair in the table.
I don't know Python - this is pseudocode
create array of scrambled alphabet
create array of "normal" alphabet
foreach char in message, find char in scrambled array, then output corresponding "normal" char
You could make a dictionary:
alphabet({'a':'alpha', 'b':'bravo','c':'charlie', etc.})
so abc would translate to alphabravocharlie
where 'a','b',.. are the coded letters and 'alpha','bravo',... are their actual values. Make "cypher" by reversing this.
See the section of online tutorials on dictionaries:
http://docs.python.org/dev/library/collections.html
I believe you're asking 'If I type in a string of characters (I'm assuming a string with no delimiter), how can I make that a dictionary where the first letter = A, the second = B, etc.' (sorry if this is the incorrect interpretation). If that is the case, you could do something like this (note the usage of raw_input - input is a built-in that evaluates the parameter - it will not assign):
alphabet = raw_input("Please input the scrambled alphabet in order: ")
message = raw_input("Now input the scrambled message: ")
secret_map = {}
# Step through the provided string, incrementing the character number by index.
# Index will start at 65 + 0 = A (change to 98 if you want lowercase)
for index, letter in enumerate(alphabet):
secret_map[letter] = chr(65 + index)
# Now join the string together, mapping each letter to its corresponding value
new_str = ''.join([secret_map[char] for char in message])
# Print the resulting string
print new_str
Since this is homework (and perhaps you haven't gotten to list comprehensions), this is equivalent to creating new_str:
new_str = ''
for letter in message:
new_str += secret_map[letter]
Let me know if this isn't what you were looking for.
I just couldn't resist expanding on stummjr's answer to create a more pythonic version of both encoding and decoding (I added some extra variables to try and make each step more clear):
import random, string
cypher_list = list(string.ascii_lowercase)
random.shuffle(cypher_list)
cypher_text = ''.join(cypher_list)
encode_tab = string.maketrans(string.ascii_lowercase, cypher_text)
decode_tab = string.maketrans(cypher_text, string.ascii_lowercase)
orig_text = 'this means war'
crypt_text = orig_text.translate(encode_tab)
clear_text = crypt_text.translate(decode_tab)
print cypher_text
print crypt_text
print clear_text
assert(clear_text == orig_text)