I'm very new to python so bear with me. I'm putting together a little crypto puzzle and part of it requires a substitution cipher. In this case each letter is replaced with three random letters. Every time I run this code it throws an error when I try to encrypt something:
Traceback (most recent call last):
File "/home/pi/Desktop/expansion cipher.py", line 159, in <module>
crypt()
File "/home/pi/Desktop/expansion cipher.py", line 142, in crypt
print encrypt(txt)
File "/home/pi/Desktop/expansion cipher.py", line 127, in encrypt
ctxt = ctxt + exp_ciph(ptxt[counter])
File "/home/pi/Desktop/expansion cipher.py", line 121, in exp_ciph
return cur_exp
UnboundLocalError: local variable 'cur_exp' referenced before assignment
Here is my code:
def rev_ciph(char):
if char == "gps":
cur_rev = "_"
if char == "evl":
cur_rev = "."
if char == "jkb":
cur_rev = "e"
if char == "bhj":
cur_rev = "t"
if char == "szk":
cur_rev = "a"
if char == "nwu":
cur_rev = "o"
if char == "dpl":
cur_rev = "i"
if char == "sbg":
cur_rev = "n"
if char == "dsl":
cur_rev = "s"
if char == "yhq":
cur_rev = "p"
if char == "sav":
cur_rev = "h"
if char == "gfs":
cur_rev = ","
if char == "rtg":
cur_rev = "d"
if char == "fqu":
cur_rev = "l"
if char == "rjt":
cur_rev = "u"
if char == "sbv":
cur_rev = "c"
if char == "yqm":
cur_rev = "m"
if char == "ywh":
cur_rev = "f"
if char == "drt":
cur_rev = "y"
if char == "zfd":
cur_rev = "w"
if char == "asn":
cur_rev = "g"
if char == "fzj":
cur_rev = "p"
if char == "rka":
cur_rev = "b"
if char == "kzv":
cur_rev = "v"
if char == "lah":
cur_rev = "k"
if char == "rma":
cur_rev = "x"
if char == "fqn":
cur_rev = "q"
if char == "vrq":
cur_rev = "j"
if char == "tfv":
cur_rev = "z"
return cur_rev
def exp_ciph(char):
if char == "_":
cur_exp = "gps"
if char == ".":
cur_exp = "evl"
if char == "e":
cur_exp = "jkb"
if char == "t":
cur_exp = "bhj"
if char == "a":
cur_exp = "szk"
if char == "o":
cur_exp = "nwu"
if char == "i":
cur_exp = "dpl"
if char == "n":
cur_exp = "sbg"
if char == "s":
cur_exp = "dsl"
if char == "p":
cur_exp = "yhq"
if char == "h":
cur_exp = "sav"
if char == ",":
cur_exp = "gfs"
if char == "d":
cur_exp = "rtg"
if char == "l":
cur_exp = "fqu"
if char == "u":
cur_exp = "rjt"
if char == "c":
cur_exp = "sbv"
if char == "m":
cur_exp = "yqm"
if char == "f":
cur_exp = "ywh"
if char == "y":
cur_exp = "drt"
if char == "w":
cur_exp = "zfd"
if char == "g":
cur_exp = "asn"
if char == "p":
cur_exp = "fzj"
if char == "b":
cur_exp = "rka"
if char == "v":
cur_exp = "kzv"
if char == "k":
cur_exp = "lah"
if char == "x":
cur_exp = "rma"
if char == "q":
cur_exp = "fqn"
if char == "j":
cur_exp = "vrq"
if char == "z":
cur_exp = "tfv"
return cur_exp
def encrypt(ptxt):
ctxt = "Ciphertext: "
counter = 0
while counter <= len(ptxt):
ctxt = ctxt + exp_ciph(ptxt[counter])
counter += 1
return ctxt
def decrypt(ctxt):
ptxt = "Plaintext: "
counter = 0
while counter <= len(ctxt):
ptxt = ptxt + rev_ciph(ctxt[counter])
counter += 1
return ptxt
def crypt():
print
txt = raw_input("Plaintext: ")
print encrypt(txt)
print
def ucrypt():
print
txt = raw_input("Ciphertext: ")
print decrypt(txt)
print
ex_code = False
while ex_code == False:
print "(1) Encrypt"
print "(2) Decript"
print "(3) Exit"
print
mchoc = raw_input("What would you like to do(1,2,3?): ")
if mchoc == "1":
crypt()
if mchoc == "2":
ucrypt()
if mchoc == "3":
ex_code = True
print
You have two problems. The first is that you aren't handling all possible inputs. Having just copied and tested you code, I see that you get UnboundLocalError: local variable 'cur_exp' referenced before assignment if and only if you try to encrypt something that includes a character that isn't handled by exp_ciph(char) (or rev_ciph(char) for that matter). Neither of these functions handles capital letters, for instance. Python is ALWAYS case sensitive, and regards capital and lower case letters as entirely different characters. Your functions also don't handle other characters, such as "," and ";". If you give the program a string to encrypt that includes a character not handled by your first two functions, then, when that character comes up, all of the conditions for the if statements in these functions are false, and thus cur_exp is never created and assigned a value. When one of these functions then tries to return cur_exp, it finds that cur_exp doesn't exist. That is the source of the error you describe above.
If you input a string consisting ONLY of lower case letters and possibly "_", the you get an entirely different error, namely:
IndexError: string index out of range
This is because the function encrypt(ptxt) always goes looking for one more character than a string has. In Python (and, I think, every programming language) the elements in an iterable such as a string or a list are indexed by their OFFSET from the first item; that is, how many items are in front of it. So, if you have a string foo with 4 charachters:
foo = "abcd"
then:
foo[0] == "a"
foo[1] == "b"
foo[2] == "c"
foo[3] == "d"
There is no foo[4]. Calling foo[4] will raise exactly the above error. The len(object) function returns the number of items in an iterable. So, keeping with the above example,
len(foo) == 4
and thus calling
foo[len(foo)]
will raise IndexError:. This is EXACTLY what always happens in your encrypt(ptxt) function here
counter = 0
while counter <= len(ptxt):
ctxt = ctxt + exp_ciph(ptxt[counter])
counter += 1
You will want to do this instead:
counter = 0
while counter <= len(ptxt) - 1:
ctxt = ctxt + exp_ciph(ptxt[counter])
counter += 1
Those are the first two problem I encounter running this. I won't guarantee there are no more. Hopefully this gets you farther down the path though.
Related
I have a task to find if a word starts with an o ends with a t or both. For finding if it starts or ends the code works fine . For the both part it doesn't work but I cant find the problem. It should return onetwo if the word starts with o and ends with t.
def one_two(word):
if word[0] == "o":
return "one"
if word[-1] == "t":
return "two"
if word[0] == "o" and word[-1] == "t":
return "onetwo"
assert (one_two("only") == "one")
assert (one_two("cart") == "two")
assert (one_two("o+++t") == "onetwo")
You need to check first if both conditions are true, if not the both case would never execute:
def one_two(word):
if word == "":
return "empty"
if word[0] == "o" and word[-1] == "t":
return "onetwo"
elif word[0] == "o":
return "one"
elif word[-1] == "t":
return "two"
print(one_two("only") == "one")
print(one_two("cart") == "two")
print(one_two("o+++t") == "onetwo")
As already mentioned, you'd need to check the last condition first, as it's checking both the first and last letter. Note that you can keep the multiple if statements if you want, rather than switch to use elif, because the return statements break out of the function early in any case.
def one_two(word):
try:
fw, *_, lw = word
except ValueError: # empty string, or string is too short
if not word:
return None
fw, lw = word, word
if (fw, lw) == ('o', 't'):
return 'onetwo'
if fw == 'o':
return 'one'
if lw == 't':
return 'two'
assert (one_two("only") == "one")
assert (one_two("cart") == "two")
print(one_two("o+++t"))
assert (one_two("o+++t") == "onetwo")
# edge cases
assert one_two('') is None
assert one_two('o') == 'one'
assert one_two('t') == 'two'
assert one_two('ot') == 'onetwo'
you are saying return so code doesn't continue
you can try check it otherway around or simply go like this:
def one_two(word):
msg = ""
if word[0] == "o":
msg += "one"
if word[-1] == "t":
msg += "two"
return msg
assert (one_two("only") == "one")
assert (one_two("cart") == "two")
assert (one_two("o+++t") == "onetwo")
def one_two(word):
return {'o': 'one'}.get(word[0], '') + {'t': 'two'}.get(word[-1], '') if len(word) else ''
I am making a language in python called PythonScript, which is a JavaScript and Python (not Python 3) mix.
I am adding variables, but when I do the following code I don't get the expected result.
var scuffles = hi!
I have tried to debug it, and as you will see in my code I made a debugging array, which I found to be empty. I looked up some tutorials, but none were covering what I am trying to do.
This is a portion of the file:
import os
import sys
programDebugingArray1 = []
functions = ["Console"]
functionCodes = [["out \"TEST\""]]
programVariables = {}
def lex(cm,stri,nums,toWake):
i = 0
if cm == "":
console()
elif cm == "var" or cm == "=":
pass
elif cm == "--vars":
print(programVariables)
elif cm == "--debugManual1":
print(programDebugingArray1)
else:
print("\""+cm+"\" was not recognized as a PythonScript command.")
console()
def console():
commandToRun = ""
tok = ""
string = ""
varValue = ""
newVarName = ""
Strings = []
Numbers = []
functionToCall = ""
state = 0
command = input()
for char in command:
tok += char
if state == 1:
string += char
elif state == 2:
if char == " ":
char = ""
newVarName += char
elif state == 3:
varValue += char
if (tok == "\"" or tok == "'") or (char == "\"" or char == "'"):
if state == 0:
state = 1
elif state == 1:
state = 0
string = string[0:len(string) - 1]
Strings.append(string)
string = ""
tok = ""
char = ""
elif tok == " ":
tok = ""
elif tok == "var" and state == 0:
state = 2
tok = ""
elif tok == "=" and state == 2:
state = 3
tok = ""
elif tok == "!" and state == 3:
programDebugingArray1.append(newVarName)
programDebugingArray1.append(varValue)
state == 0
programVariables[newVarName] = varValue
tok = ""
elif tok == "--vars" and state == 0:
commandToRun == "--vars"
tok = ""
elif tok == "--debugManual1" and state == 0:
commandToRun == "--debugManual1"
tok = ""
if commandToRun == "":
commandToRun = command
lex(commandToRun,Strings,Numbers,functionToCall)
console()
I expected the debug array to at least have something in it, but for some reason it and the variables dictionary is empty. There are no error messages or boots out of the console.
I don't know what to add. At the time that's why I only posted the code.
But the intended result is that a string should be parsed (and successfully printed).
I don't remember what the issue was, but by the sounds of it, it probably just didn't print.
(I'm doing this to get back on S.O.'s "good side".)
class Lex:
def run(args, string):
if args == "print":
print(str(string))
class Calin:
string = ""
running = ""
def parse(args):
lexic = Lex
string = ""
tok = ""
state = 0
for char in args:
tok += char
if tok == " ":
if state == 0:
tok = ""
elif state == 1:
tok = " "
elif tok == "\"":
if state == 0:
state = 1
elif state == 1:
state = 0
elif state == 1:
string += char
elif tok == "print":
running = "print"
lexic.run(running, string)
trans = Calin
trans.parse("print \"WOW A STRING\"")
Because you are making state == 1 only when tok == "\"", which never happens (You are keep adding strs to it.). Changing it to char works:
class Lex:
def run(args, string):
if args == "print":
print(str(string))
class Calin:
string = ""
running = ""
def parse(args):
lexic = Lex
string = ""
tok = ""
state = 0
for char in args:
tok += char
if tok == " ":
if state == 0:
tok = ""
elif state == 1:
tok = " "
elif char == "\"": # <<< Change this
if state == 0:
state = 1
elif state == 1:
state = 0
elif state == 1:
string += char
elif tok == "print":
running = "print"
lexic.run(running, string)
trans = Calin
trans.parse("print \"WOW A STRING\"")
# WOW A STRING
i'm using python 3 and i would like to know how to count the amount of times a set of 3 letters comes up in a sentence:
con = ""
count = 0
for i in mystery_string:
if i == "c":
con = "c"
if i == "a" and con == "c":
con = "ca"
if i == "t" and con == "ca":
con = "cat"
if con == "cat":
count +=1
con = ""
print (count)
this is the code i have so far, however it doesn't seem to work for every case
can someone help me
the thing i also need to explain is that i cannot use the builtin function count()
just do the following
mystery_string.count('cat')
you can use slicing:
word='cat'
count = 0
for i in range(len(mystery_string)-len(word)+1):
if mystery_string[i:i+len(word)]==word:
count +=1
print (count)
mystery_string = "my cat your cat"
count = 0
current_search_letter = "c"
if letter == "c":
current_search_letter = "a"
elif letter == "a" and current_search_letter == "a":
current_search_letter = "t"
elif letter == "t" and current_search_letter == "t":
count += 1
current_search_letter = "c"
else:
current_search_letter = "c"
print(count)
For some reason I get an error in python 2.7 when running this and entering in my 26 letter key. It says that the list index is out of range. Any help would be greatly appreciated. Thanks! (And I know I could've used a loop for the encrypter)
#-------------------------#
# Code Translator #
#-------------------------#
message = ''
messagearray = []
user = ''
encrypted = []
decrypted = []
keystring = ''
alphabet = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z']
dataset = []
keyarray = []
def encrypter():
keystring = raw_input("Please paste key: ")
message = raw_input("Message to Encrypt: ")
for char in message:
if char == alphabet[0]:
messagearray.append(keyarray[0])
elif char == alphabet[1]:
messagearray.append(keyarray[1])
elif char == alphabet[2]:
messagearray.append(keyarray[2])
elif char == alphabet[3]:
messagearray.append(keyarray[3])
elif char == alphabet[4]:
messagearray.append(keyarray[4])
elif char == alphabet[5]:
messagearray.append(keyarray[5])
elif char == alphabet[6]:
messagearray.append(keyarray[6])
elif char == alphabet[7]:
messagearray.append(keyarray[7])
elif char == alphabet[8]:
messagearray.append(keyarray[8])
elif char == alphabet[9]:
messagearray.append(keyarray[9])
elif char == alphabet[10]:
messagearray.append(keyarray[10])
elif char == alphabet[11]:
messagearray.append(keyarray[11])
elif char == alphabet[12]:
messagearray.append(keyarray[12])
elif char == alphabet[13]:
messagearray.append(keyarray[13])
elif char == alphabet[14]:
messagearray.append(keyarray[14])
elif char == alphabet[15]:
messagearray.append(keyarray[15])
elif char == alphabet[16]:
messagearray.append(keyarray[16])
elif char == alphabet[17]:
messagearray.append(keyarray[17])
elif char == alphabet[18]:
messagearray.append(keyarray[18])
elif char == alphabet[19]:
messagearray.append(keyarray[19])
elif char == alphabet[20]:
messagearray.append(keyarray[20])
elif char == alphabet[21]:
messagearray.append(keyarray[21])
elif char == alphabet[22]:
messagearray.append(keyarray[22])
elif char == alphabet[23]:
messagearray.append(keyarray[23])
elif char == alphabet[24]:
messagearray.append(keyarray[24])
elif char == alphabet[25]:
messagearray.append(keyarray[25])
print ''.join(messagearray)
def decrypter():
keystring = raw_input("Please paste key: ")
message = raw_input("Message to Decrypt: ")
def outputM():
print decrypted
def userChoice():
user = raw_input("Encrypt or Decrypt?")
if user.upper() == "ENCRYPT":
encrypter()
elif user.upper() == "DECRYPT":
decrypter()
else:
print "Please enter a valid command."
userChoice()
for char in keystring:
keyarray.append(char)
userChoice()
Here's the full traceback I get:
Traceback (most recent call last):
File "translate.py", line 102, in <module>
userChoice()
File "translate.py", line 92, in userChoice
encrypter()
File "translate.py", line 43, in encrypter
messagearray.append(keyarray[11])
IndexError: list index out of range
The problem is here:
for char in keystring:
keyarray.append(char)
keystring is empty so also keyarray will remain empty. In order not to have IndexError you would need a keystring as much longer as the alphabet (since basically you are just substituting chars)
The problem is that in:
def decrypter():
keystring = raw_input("Please paste key: ")
message = raw_input("Message to Decrypt: ")
you are assigning the values to local variables, so the global ones remain empty. If you want to modify the global variables you have to state so:
def decrypter():
global keystring, message
keystring = raw_input("Please paste key: ")
message = raw_input("Message to Decrypt: ")
the same is true for encrypter.
Also, you cannot create keyarray before having taken some input!
There are also many other issues with the code. You cannot possibly think that doing all the manual indexing is the best way to proceed. What if you want to support a 128 character alphabet?
Use loops:
for char in message:
for i, c in enumerate(alphabet):
if char == c:
messagearray.append(keyarray[i])
(Instead of all those repeating lines).
Moreover strings already provide a method to do exactly what you are trying to do. It's called translate.
You could simply do:
import string
table = str.maketrans(string.ascii_lowercase, keystring)
And then use:
decrypted_text = some_encrypted_text.translate(table)
example run:
In [1]: import string
...: alphabet = string.ascii_lowercase
...: table = str.maketrans(alphabet, alphabet[3:]+alphabet[:3])
...:
In [2]: 'hello'.translate(table)
Out[2]: 'khoor'
The above is for python3+. In python2.7 you have to use string.maketrans instead of str.maketrans. So you'd have to do:
In [1]: import string
...: alphabet = string.ascii_lowercase
...: table = string.maketrans(alphabet, alphabet[3:]+alphabet[:3])
...:
In [2]: 'hello'.translate(table)
Out[2]: 'khoor'