for loop result is printed twice - python

note: the letters are there twice so when shifting a letter at the end of the alphabet i dont get a out of range error
so currently im working on a caesers cypher where you write a word and shift those letters by a certain amount of times
input = abc
output = bcd
my issue is when the code runs it prints the output letters twice
input = abc
output = bbccdd
heres my code
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', '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']
direction = input("Type 'encode' to encrypt, type 'decode' to decrypt:\n")
text = input("Type your message:\n").lower()
shift = int(input("Type the shift number:\n"))
def encrypt(text, shift):
cipher_text = ""
for i in text:
for letter in alphabet:
if i == letter:
index = alphabet.index(letter)
shifted_index = index + shift
shifted_letter = alphabet[shifted_index]
cipher_text += shifted_letter
print(f"The encoded word is {cipher_text}")
encrypt(text, shift)
another example
input = zulu
expected output = avmv
code output = aavvmmvv

Lots of work for what is essentially a one-liner:
import string
alphabet = string.ascii_lowercase # use the predefined string of lower case letters from the string module
index = {ch: i for i, ch in enumerate(alphabet)} # pre-calculate the index of each character once.
def encrypt(txt, n):
return ''.join(alphabet[(index[c] + n) % len(alphabet)] for c in txt)
print(encrypt('spin', 5))
prints
xuns
the modulo operation (ie. ... % len(alphabet)) makes sure the index is within bounds of the alphabet after adding the shift - no matter how big the shift is.

leave it at "for i in text" their is no need for "for letter in alphabet" that is why it is looping through. If that doesnt work take out the duplicates in your alphabet. I didnt notice that on first glance.

Remove the inner for loop and the if and then find the first index of the current character in the alphabet.
def encrypt(text, shift):
cipher_text = ""
for i in text:
index = alphabet.index(i)
shifted_index = index + shift
shifted_letter = alphabet[shifted_index]
cipher_text += shifted_letter
print(f"The encoded word is {cipher_text}")
This code sticks closely to your approach. There are better solutions, like the one from #thebjorn.

As mentioned above, you have the same alphabet twice. So, you need to exit the inner for loop once you have shifted. So, add a break after cipher_text += shifted_letter, that will exit the inner for loop.
Updated Code
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', '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']
direction = input("Type 'encode' to encrypt, type 'decode' to decrypt:\n")
text = input("Type your message:\n").lower()
#shift = int(input("Type the shift number:\n"))
def encrypt(text, shift):
cipher_text = ""
for i in text:
for letter in alphabet:
if i == letter:
index = alphabet.index(letter)
shifted_index = index + shift
shifted_letter = alphabet[shifted_index]
cipher_text += shifted_letter
break # NEW LINE
print(f"The encoded word is {cipher_text}")
shift = int(input("Type the shift number:\n"))
if shift > 26:
print("Shift should be max 26, exiting...")
else:
encrypt(text, shift)
Output
Type 'encode' to encrypt, type 'decode' to decrypt:
encode
Type your message:
spin
Type the shift number:
5
The encoded word is xuns
Updated based on feedback
import string
direction = input("Type 'encode' to encrypt, type 'decode' to decrypt:\n")
text = input("Type your message:\n").lower()
shift = int(input("Type the shift number:\n"))
alphabet = string.ascii_lowercase # use the predefined string of lower case letters from the string module
index = {ch: i for i, ch in enumerate(alphabet)} # pre-calculate the index of each character once.
def encrypt(txt, n):
return ''.join(alphabet[(index[c] + n) % len(alphabet)] for c in txt)
encrypt(text, shift)
Output
Type 'encode' to encrypt, type 'decode' to decrypt:
encode
Type your message:
xylophone
Type the shift number:
100
'tuhkldkja'

Related

list out of range. Loop list in python

Can you please help me with my problem ? in line 28 says list index out of range.
I tried change for i in list to for i in range(len(message)) but it didn't help.
Thanks for help
letter = [
'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',
]
falseletters = [
'r', 's', 't','u', 'v', 'w', 'x','y', 'z',
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
'i', 'j', 'k', 'l','m', 'n', 'o', 'p', 'q',
]
message = [
]
def writing():
print("start writing")
print("write ,,end'' to end")
x = True
while x:
b = input(">>")
if b == 'end':
x = False
nour = 0
for i in range(len(message)):
nour = nour + 1
check = message[nour]
if check in [falseletters]:
print(falseletters[nour])
if check not in [falseletters]:
print(check)
if b != 'end':
message.append(b)
print("added", b)
writing()
There's several errors in your code: however, the core of your problem I believe lies in the fact that you're not iterating over each letter over each word in the message list, rather you're checking if any of the words is in falseletters. Here's a working example of what I believe you're trying to accomplish:
letters = "abcdefghijklmnopqrstuvwxyz"
falseletters = "rstuvwxyzabcdefghijklmnopq"
def mapper(letter: str) -> str:
return falseletters[letters.index(letter)]
message = []
def writing():
print("start writing")
print("write ,,end'' to end")
x = True
while x:
b = input(">>")
if b == "end":
x = False
for check in message:
print("".join(map(mapper, check)))
else:
message.append(b)
print("added", b)
writing()
It takes each word in message, and maps each letter of the word to the false letter. Then, each mapped character is printed as a string.

Inserting breaks in variables over a certain length

So basically what I want to do is if the random string of characters generated is over 6 chars long it adds a space in a random place in that string and then the remaining ones are added on after the space so for example: raw output: "aoneicse", what I want : "aoneic se" or "aone icse".
Here is my code:
import random
alist = [' ', 'a', 'b', 'c', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']
blist = [' ', 'a', 'b', 'c', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']
clist = [' ', 'a', 'b', 'c', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']
# define the 3 words
a = ''.join(random.choices(alist, k = random.randint(2,8)))
b = ''.join(random.choices(blist, k = random.randint(2,8)))
c = ''.join(random.choices(clist, k = random.randint(2,8)))
# each letter is a certain word, if this word exceeds 6 characters add a space in a random place
if a length = > 6:
asp = [a + " "]
if b length = > 6:
bsp = [b + " "]
if c length = > 6:
csp = [c + " "]
# or something along the lines of this i guess
This code does not currently work, BTW.
You don't need to create a list of strings with every letter of the alphabet, there's already a string module that does that for you:
import string
print(' ' + string.ascii_lowercase)
# Outputs abcdefghijklmnopqrstuvwxyz
You also don't need to create three different variables, you can just use a single one and use that:
import string
base_str = ' ' + string.ascii_lowercase
Then, you can use a list to generate your words based on this string:
import random
import string
base_str = ' ' + string.ascii_lowercase
words = [''.join(random.choices(base_str, k=random.randint(2,8))) for _ in range(3)]
Now, just apply your space requirement to each word:
import random
import string
base_str = ' ' + string.ascii_lowercase
words = [''.join(random.choices(base_str, k=random.randint(2,8))) for _ in range(3)]
new_words = []
for word in words:
if len(word) < 6:
new_word = word
else:
pos = random.randrange(len(word))
new_word = word[:pos] + ' ' + word[pos:]
new_words.append(new_word)
Using random.seed(0), new_words is equal to ['j xazmxvz', 'oxmg', 'buzns pcb'].
Don't join the choices immediately. Generate the list, and if it is long enough, pick an index in the middle (sufficiently far from either end, depending on your needs), and perform a slice assignment to the empty list at that position. Then join the list into a single string.
import string
a = random.choices(string.ascii_lowercase, k=random.randint(2,8))
if len(a) > 6:
# Adjust the arguments to randint as desired
x = random.randint(2, len(a) - 2)
a[x:x] = ' '
a = ''.join(a)
import random
character = list(map(chr, range(ord('a'), ord('z') + 1)))
def get_char():
return character[random.randint(0, len(character) - 1)]
def gen_word(min_len, max_len):
word = [get_char() for _ in range(random.randint(min_len, max_len))]
if len(word) > 6:
word[random.randint(1, len(word) - 2)] = ' '
return ''.join(word)
for i in range(10):
print(gen_word(4, 10))
Iā€™d use slices to return a space, sliced-in at the right spot; Something along the lines of:
def split(input_str):
if len(input_str) > 6:
space_at = rand(0,len(input_str))
return input_str[:space_at] + ā€˜ ā€˜ + input_str[space_at:]
else:
return input_str

TypeError: can only concatenate str (not "int") to str (I don't think that should happen)

I decided it would be a cool idea to make a translator to a custom language, so I tried making one. However, I am fairly new to python, and I cannot figure out why it is expecting a string instead of an integer. What I am trying to do is make it so if you enter in a word such as 'bin', it will go to the next consonant/vowel for each, so 'bin' ends up as 'cop' as the next consonant after 'b' is 'c', the next vowel after 'i' is 'o' and the next consonant after 'n' is 'p'.
consonants = ['b', 'c', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'm', 'n', 'p', 'q', 'r', 's', 't', 'v', 'w', 'x', 'y', 'z']
vowels = ['a', 'e', 'i', 'o', 'u']
translated_word = ''
word_to_translate = input('Enter in the word to translate! ')
for letter in range(len(word_to_translate)):
new_letter = word_to_translate[letter - 1]
if new_letter in consonants:
l = (consonants[:new_letter + 1])
translated_word = translated_word + str(l)
elif new_letter in vowels:
l = (vowels[:new_letter + 1])
translated_word = translated_word + str(l)
print(translated_word)
consonants = ['b', 'c', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'm', 'n', 'p', 'q', 'r', 's', 't', 'v', 'w', 'x', 'y', 'z']
vowels = ['a', 'e', 'i', 'o', 'u']
translated_word = ''
word_to_translate = input('Enter in the word to translate! ')
for i in word_to_translate:
if i in consonants:
ind = consonants.index(i)
translated_word += consonants[ind+1]
elif i in vowels:
ind = vowels.index(i)
translated_word += vowels[ind+1]
print (translated_word)

Python: TypeError: unsupported operand type(s) for +: 'Random' and 'str'

I'm entering a code where a word is randomly generated. But it says TypeError and that random can't be matched with string
I've tried rewriting code multiple times but it didn't work.
Code:
import random
from random import *
Letters = ['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']
LettersInWord = Random()
Points = 0
print(LettersInWord + " is number of letters in word")
for index in range(LettersInWord):
Word = Letters[Random.random(0, 25)]
Guess = input("Enter Word You Think It Is (You will get a point everytime
one or more of your letters match with the word. Your turn will end when
you enter a letter that is not in the word: ")
for letter in Guess:
if letter == letter in Word:
Points = Points + 1
if Guess == Word:
print("Congratulations, you won. End program and restart to
try again.")
Guess = input("Well done, try again")
Random() is a random-number generator, not a number itself.
letters_in_word = randint(1,25) # random number between 1 and 25, inclusive
(Capitalized names are conventionally reserved for class names. Use snake case identifiers for ordinary variables.)
Continuing from the comments:
from random import *
Letters = ['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']
while True:
letters_in_word = randint(1,25)
Points = 0
Word = []
print("{} is number of letters in word".format(letters_in_word))
for index in range(0, letters_in_word):
Word.append(Letters[randint(0, 25)])
Guess = input("Press Q/q to exit or Enter Word You Think It Is (You will get a point everytime one or more of your letters match with the word. Your turn will end when you enter a letter that is not in the word: ")
if Guess.lower() == 'q':
break
print(Word)
if Guess in Word:
Points = 100 # assuming
print("Congratulations, you won. End program and restart to try again.\nTotal Points: {}".format(Points))
break
else:
for letter in Guess:
if letter in Word:
Points = Points + 1
print("Total Points: {}".format(Points))
OUTPUT:
10 is number of letters in word
Press Q/q to exit or Enter Word You Think It Is (You will get a point everytime one or more of your letters match with the word. Your turn will end when you enter a letter that is not in the word: pak
['f', 't', 'l', 'b', 'd', 'k', 'e', 'p', 'd', 'n']
Total Points: 2
9 is number of letters in word
Press Q/q to exit or Enter Word You Think It Is (You will get a point everytime one or more of your letters match with the word. Your turn will end when you enter a letter that is not in the word: dirt
['z', 'i', 'k', 'p', 'z', 'j', 'r', 't', 'd']
Congratulations, you won. End program and restart to try again.
Total Points: 100
Process finished with exit code 0

How to write code that checks to see if item is negative before split?

Hey so I have a polyalphabetic cipher and it's working great but I am running into the issue of having all my inputs on one line. The inputs would be the shift;secretWord; and message. I need to find a way to check if an input is solely a negative number and if it is I need the code to exit. I also need to find a way to make my code keep looping until the negative condition is met.
alpha = ['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']
shiftChange = 0
secretWord = 0
da_message = 0
shiftChange = int(shiftChange)
inputs = []
shiftChange, secretWord, da_message = input('').split(";")
da_message = da_message.lower()
inputs.append(shiftChange)
inputs.append(secretWord)
inputs.append(da_message)
secretWord = secretWord.lower()
secretWord = secretWord * len(da_message)
cypherText = ''
symbol = ' '
count = 0
for letter in da_message:
if letter in alpha:
shift = alpha.index(secretWord[count]) + int(shiftChange)
letterIndex = alpha.index(letter) + 1
cypherLetter = alpha[(letterIndex+shift)%26]
cypherText = cypherText + cypherLetter
count = count + 1
print(cypherText.upper())
Use int().
The int() raises a ValueError for anything that isn't, entirely, an integer. Trap this error using a try-except loop and then if the error is raised, then execute the rest of your code. (since it is an alphanumeric) Otherwise, compare it if it is less than 0 and exit if true.
Below is a modified version of your code that solves both of your problems.
The while True ensures the program continues to loop until the negative number is found, which in turn causes it to exit the entire program.
alpha = ['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']
shiftChange = 0
secretWord = 0
da_message = 0
cypherText = ''
symbol = ' '
count = 0
shiftChange = int(shiftChange)
inputs = []
while True:
shiftChange, secretWord, da_message = input('enter:').split(";")
da_message = da_message.lower()
inputs.append(shiftChange)
inputs.append(secretWord)
inputs.append(da_message)
secretWord = secretWord.lower()
secretWord = secretWord * len(da_message)
for i in range(len(inputs)):
try:
temp = int(inputs[i])
except ValueError:
for letter in da_message:
if letter in alpha:
shift = alpha.index(secretWord[count]) + int(shiftChange)
letterIndex = alpha.index(letter) + 1
cypherLetter = alpha[(letterIndex+shift)%26]
cypherText = cypherText + cypherLetter
count = count + 1
print(cypherText.upper())
if temp < 0:
exit()
Hope this helps!

Categories

Resources