How to let user end program and shift list - python

Im trying to make an encryption program
def intro():
msg = input("Enter the message you wish to encrypt: ")
return msg
def shift(msg):
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']
rotate = int(input("The level of the encryption?: "))
text = ""
for ch in msg:
if ch == " " or ch == ".":
pass
elif msg == "$":
print("nah")
else:
index = alpha.index(ch)
newindex = index + rotate
new= alpha[newindex]
text += new
return text
def start():
msg = intro()
text = shift(msg)
print("Your encryptions is: " + text)
start()
I can't figure out a way to loop the list without getting an index out of range error. For example, if you put "z" it will shift to an "a". I also need for my program to loop till user inputs to end it. I just started coding in python a few months ago so any help will be appreciated!beginner

All you need to do is add this line
newindex %= len(alpha)
Detailed Change (with context)
index = alpha.index(ch)
newindex = index + rotate
new= alpha[newindex]
text += new
to
index = alpha.index(ch)
newindex = index + rotate
newindex %= len(alpha) # <--- this is the new line
new= alpha[newindex]
text += new
This will automatically make the new index loop so it never goes past the end!
Working example
>> Enter the message you wish to encrypt: 'xyz'
>> The level of the encryption?: 2
>> Your encryptions is: zab

Since your code is running fine, I can tell you about some techniques you can work on to get the functionality you want.
To get an array that loops around, you can use a mod system. For example 8 mod 3 = 2 and it would be coded remainder = 8 % 3. If you had a mod size 26, i.e. the alphabet, you could take the remainder of the total number and use it as an index in your alphabet list. This would cycle around when the total number is greater than 26 and begin again at a.
To get the program to end on user input, you can use a variety of methods such as keyboard interrupts, recognizing certain commands such as ctrl-c or whole words. Here is a start from a previous stackoverflow question. How to kill a while loop with a keystroke?

use the modulus operator to wrap the index around when it's outside the list length:
newindex = (index + rotate) % len(alpha)
To repeat, use a while True: loop, and use break to end it.
def start():
while True:
msg = intro()
if msg == '':
break
text = shift(msg)
print("Your encryptions is: " + text)
This will end when the user inputs an empty line.

Related

Can you explain me the RLE algorithm code in python

I I've finally found how to make a RLE algorithm by watching a tutorial but This tutorial didn' t explain something in that code I didn't get why we write j = i instead of j = 0 (Knowing that I = 0) it's the same no ?
I didn't get why i = j + 1 either. Why i = j + 1 At the end of the function ? Why not simply i += 1 but if we want to repeat a loop in a loop then we do j + 1 ?
Did the first while loop is supposed to repeat the second while loop until the string is finished ?
And finally why encoded_message is repeated two times ? instead of one. We return encoded_message so that's it ? We can simply do print(encode(text)) instead of
"print('The encoded message is the output ',encoded_message)" (when we put encode(text) into encoded_message)
I know i'm asking a lot of questions but I just can't memorize the code without understanding it, it would be totally useless and unproductive
def encode(message):
encoded_message = ""
i = 0
while(i<len(message)):
count = 1
ch = message[i]
j = i # ???
while(j<len(message)-1): # GET IT -----------------------------------------------------------
if message[j] == message[j+1]: # if the previous and next characters are the same
count = count + 1 # we increase count variable
j += 1 # we increase j position
# GET IT ----------------------------------------------------------------------------
else:
break
encoded_message = encoded_message + str(count) + ch # "" + count converted to string + character (ch)
i = j + 1 # ???
return encoded_message
text = input('enter your charcter chain...')
encoded_message = encode(text)
print('The encoded message is the output ',encoded_message)
When I replaced j = i by j = 0 nothing is displayed in the terminal
see : no result
There is an outer loop and an inner loop. The outer loop with the variable i starts iterating over the message. The inner loop uses the variable j and starts at the current position of i.
That is: when i=0 then j=0. But when i=5 (for example) then j=5 also.
The inner loops task is to check whether 2 or more identical characters follow one another. If they do i is increased accordingly at the end of the inner loop. So that each letter of the message is only looked at once.
That is why j should not be set to a constant value. Setting it to j=0 would cause the inner loop to start at the beginning of the message at every iteration.
I added two simple print() statements to your code to clarify:
def encode(message):
encoded_message = ""
i = 0
while(i<len(message)):
print(f'outer loop: i={i}')
count = 1
ch = message[i]
j = i
while(j<len(message)-1):
print(f'\tinner loop: j={j}')
if message[j] == message[j+1]: # if the previous and next characters are the same
count = count + 1 # we increase count variable
j += 1 # we increase j position
else:
break
encoded_message = encoded_message + str(count) + ch # "" + count converted to string + character (ch)
i = j + 1
return encoded_message
text = 'Hello World'
encoded_message = encode(text)
print('The encoded message is the output ', encoded_message)
(Please note: I do not know the RLE algorithm but just looked at your code.)

Why is my function not prompting me to enter input?

I’m using Python IDE 3. My goal is this: If I have a string of text, ‘ABCDEFGHIJKL’, I want to sort it into groups, like three groups (‘ADGJ’,’BEHK’,’CFIL’). I require input for this, but the prompts aren’t showing up and I can’t type in input. Here’s my code:
#data
code_text = input('Text: ').lower()
code_skip = int(input('Shift length: '))
code_list = []
#function
def countSkip(text, shift, listt):
i = 0
group = 1
if group <= shift:
for e in text:
#make sure the set starts at the right place
if e.index()+1 < group:
pass
elif shift != 0:
if i = shift:
listt.append(e)
i = 0
i += 1
else:
listt.append(e)
group += 1
Calling the function
countSkip(code_text, code_shift, code_list)
There's a few things stopping your code from working that people have pointed out in the comments. Instead of trying to dissect your code and get that to work, I wrote a much more concise function that will get you the results you're after
def text_splitter(input_text, set_length):
num_sets = int(len(input_text)/set_length)
split_text = ["".join([input_text[(n * num_sets) + m] for n in range(set_length)]) for m in range(num_sets)]
return split_text
text_to_split = input('Text: ').lower()
len_set = int(input('Set Length: '))
text_list = text_splitter(text_to_split, len_set)
Sorry I was struggling to name the variables in an effective manner but the function above uses a list expression to get you the results you need. Keep in mind that if you use say a 7 letter string and ask for sets of length 2, the last letter won't be appended. However this shouldn't be too hard to check and correct. For example you could add this code to the function or around the initial input for the set length:
while len(input_text) % set_length != 0:
set_length = int(input("The text is length " + str(len(input_text)) + " please enter a different set length: "))

Vigenère cipher: How to make it so that the encrypted message appears in a print function?

I'm a beginner in coding and in Python too. Right now I'm working on a Vigenère cipher.
I've gotten far enough to encrypt the message using a key. I added comments on each section of code for reference. Here is my code. My question is below the code.
# Ask user for message
print('type a message.')
message = input()
# print a white line for neatness
print()
# ask user for a key
print('give your key')
key = input()
# create a range with the length of the message
ran = range(len(message))
# Iterate though the range and therefor show all the letters
for i in ran:
# get current letters for this iteration
currentLetter = message[i]
currentKeyLetter = key[i % len(key)]
# Get corresponding numbers
numberLetter = ord(currentLetter)
numberKeyLetter = ord(currentKeyLetter)
# Add two letters
sumTwoLetters = numberLetter + numberKeyLetter
# Get the number of the encrypted letter
newNumberLetter = sumTwoLetters % 128
# Get the encrypted number based on number
newLetter = chr(newNumberLetter)
# print out the result
printText = currentLetter + "(" + str(numberLetter) + ") + "
printText += currentKeyLetter + "(" + str(numberKeyLetter) + ") = "
printText += newLetter + "(" + str(newNumberLetter) + ")"
print(printText)
The code asks for the user's input for the message and key. The ran variable creates a range with the length of the message.
After that, the for loop encrypts the message with the key using ord and chr
The encrypted letter is stored in the variable newLetter
the user can see what the program has done with printText
However, my question is: How can I make the encrypted text appear on a single string. I tried to do it in a loop. I failed miserably (so much so that I don't want to show it)
Does anyone have any suggestions on how to make the encrypted message appear in a single line of text?
You can gather the results in a list and then join() them all into a single string at the end after the for loop. See the comments for the changes.
...
results = [] # ADDED.
# Iterate though the range and therefor show all the letters
for i in ran:
# get current letters for this iteration
currentLetter = message[i]
currentKeyLetter = key[i % len(key)]
# Get corresponding numbers
numberLetter = ord(currentLetter)
numberKeyLetter = ord(currentKeyLetter)
# Add two letters
sumTwoLetters = numberLetter + numberKeyLetter
# Get the number of the encrypted letter
newNumberLetter = sumTwoLetters % 128
# Get the encrypted number based on number
newLetter = chr(newNumberLetter)
# print out the result
printText = currentLetter + "(" + str(numberLetter) + ") + "
printText += currentKeyLetter + "(" + str(numberKeyLetter) + ") = "
printText += newLetter + "(" + str(newNumberLetter) + ")"
results.append(printText) # PUT IN results LIST INSTEAD OF PRINTING.
print(''.join(results)) # ADDED.
There are two easy ways. Either (1) build the string inside the loop and print it outside the loop, or (2) print each character as you move through the loop but without newlines, plus one newline after the loop.
Try one of those approaches and if you need more help, add a comment. You'll learn more by trying it yourself!

String Index Out Of Range (Python) I have made bounds too

import time
password=input("What's your password?")
ans = ""
password=password.lower()
alpha = "abcdefghijklmnopqrstuvwxyz"
n = 0
a=0
starttime=time.time()
while ans !=password:
print(a)
for i in range(len(password)):
letter=alpha[n]
ans+=letter
if ans[a] != password[a]:
print(ans)
ans = ans.replace(ans[a],"")
n+=1
break
else:
a+=1
print(ans)
n=0
break
print("Password Found!")
endtime=time.time()
time=endtime-starttime
print("It took " + str(time) + " seconds!")
This is my code, sorry if i'm not posting it right (first time here). But let's digress, It seems i get an error of string index out of range
Traceback (most recent call last):
File "C:\Users\admin\Documents\Letter word cracker.py", line 15, in <module>
if ans[a] != password[a]:
IndexError: string index out of range
I was wondering how to fix this, because its been eating at my brain for days. Any help would be appreciated, thanks!
Ok, I don't know why you are trying to do this, what you are trying to do, the error is here due to this line
ans = ans.replace(ans[a],"") ---> X
what replace will do, is replace all the occurrences of a particular character from the array, while you only need to remove the last.
For example :-
If ans = "naa",
now replace will replace both 'a' while based on your logic you only want to remove the last element. because you have already matched till "na" and now in process of matching the third element.
You could probably do :-
ans = ans[:-1]
But again, this is a very very bad way to do this, because strings are immutable so you are basically creating and destroying strings every iteration.
One advice I would give is using list of characters instead of a string, it would not give a significant boost to the runtime for your program, for whatever reason you are using this.
EDIT:-
Also the for loop is unnecessary, as it is always breaking after first iteration. thanks #TigerHawk
import time
password=input("What's your password?")
ans = []
password=password.lower()
alpha = "abcdefghijklmnopqrstuvwxyz"
n = 0
a=0
starttime=time.time()
while "".join(ans) !=password:
letter=alpha[n]
ans.append(letter)
if ans[a] != password[a]:
ans.pop()
n+=1
else:
a+=1
n=0
print("Password Found!")
endtime=time.time()
time=endtime-starttime
This is a little better and more condensed version. From what I understand, you want to brute force a character string to compare it to a password.
import time
password=input("What's your password?")
password=password.lower()
alpha = "abcdefghijklmnopqrstuvwxyz"
starttime=time.time()
for letter in range(len(password)):
for index in range(len(alpha)):
if alpha[index] == password[letter]:
print "Letter",letter,"Found."
next
print "Password Found!"
endtime=time.time()
time=endtime-starttime
print "It took",time,"seconds!"
There are a few issues per the previous post, but the IndexError is happening because you are comparing each element of each list, and when one list runs out, it raises the IndexError exception. Wrap that part of the code in an if() that checks to see whether there are any more elements left over.
This will not fix the entire program, and in fact, you'll likely need a better way to do this comparison... I'm just explaining why the IndexError is happening.
if (ans[a] and password[a]):
if ans[a] != password[a]:
print(ans)
ans = ans.replace(ans[a],"")
n+=1
break
You should really go through your logic to understand why it isn't working, but there are many improvements you can make to your code. I have implemented a working version with a few improvements below.
from time import time
import string
#this will only work for a-z no whitespace, caps, numbers, etc.
pwd = raw_input("What is your password? ")
pwd = pwd.lower()
#create list of password for easier iterability
password = list(pwd)
#alphabet will have a-z lowercase
alphabet = list(string.ascii_lowercase)
#empty list to start
guess = []
#start timer
start = time()
#outer loop through password
for char in password:
#inner loop through alphabet
for letter in alphabet:
if letter == char:
guess.append(letter)
break
#print correct guess as string
end = time()
print "It took " + str(end - start) + " seconds to solve this password."
#verify correctness
print "".join(guess)
print pwd

brute force password with words and numbers

I am doing this science fair project for school: http://www.sciencebuddies.org/science-fair-projects/project_ideas/CompSci_p046.shtml#summary
The project gives you base program that guesses the passwords that you input into the program and uses a different methods to guess it. Part of the project is to come up with new algorithms to add to the program. One of the methods is using long list of common passwords to match the given password and another is a simple lock-dial simulation of numbers up to 8 digits. I was wondering if there was a way two combine those to so it checks a word in the list plus the number dial behind the word. How to write a simple code to do that?
What I'm really asking for is for someone to help me write a new method that goes through the word list and add a number dial (brute force with numbers) after the word, then check to see if that's the password inputed.
Original program and word list can be downloaded here: http://www.sciencebuddies.org/science-fair-projects/project_ideas/CompSci_p046.shtml#materials
This is the number dial simulation the program uses
def search_method_1(num_digits):
global totalguesses
result = False
a=0
#num_digits = 3 # How many digits to try. 1 = 0 to 9, 2 = 00 to 99, etc.
starttime = time.time()
tests = 0
still_searching = True
print("Using method 1 and searching for "+str(num_digits)+" digit numbers.")
while still_searching and a<(10**num_digits):
ourguess = leading_zeroes(a,num_digits)
tests = tests + 1
totalguesses = totalguesses + 1
if (check_userpass(which_password, ourguess)):
print ("Success! Password "+str(which_password)+" is " + ourguess)
still_searching = False # we can stop now - we found it!
result = True
else:
print ("Darn. " + ourguess + " is NOT the password.")
a=a+1
seconds = time.time()-starttime
report_search_time(tests, seconds)
return result
This is the code that runs through the word list:
def search_method_3(file_name):
global totalguesses
result = False
# Start by reading the list of words into a Python list
f = open(file_name)
words = f.readlines()
f.close
# We need to know how many there are
number_of_words = len(words)
print("Using method 3 with "+str(number_of_words)+" in the list")
## Depending on the file system, there may be extra characters before
## or after the words.
for i in range(0, number_of_words):
words[i] = cleanup(words[i])
# Let's try each one as the password and see what happens
starttime = time.time()
tests = 0
still_searching = True
word1count = 0 # Which word we'll try next
while still_searching:
ourguess_pass = words[word1count]
#print("Guessing: "+ourguess_pass)
# Try it the way it is in the word list
if (check_userpass(which_password, ourguess_pass)):
print ("Success! Password "+str(which_password)+" is " + ourguess_pass)
still_searching = False # we can stop now - we found it!
result = True
#else:
#print ("Darn. " + ourguess_pass + " is NOT the password.")
tests = tests + 1
totalguesses = totalguesses + 1
# Now let's try it with the first letter capitalized
if still_searching:
ourguess_pass = Cap(ourguess_pass)
#print("Guessing: "+ourguess_pass)
if (check_userpass(which_password, ourguess_pass)):
print ("Success! Password "+str(which_password)+" is " + ourguess_pass)
still_searching = False # we can stop now - we found it!
result = True
#else:
#print ("Darn. " + ourguess_pass + " is NOT the password.")
tests = tests + 1
totalguesses = totalguesses + 1
word1count = word1count + 1
if (word1count >= number_of_words):
still_searching = False
seconds = time.time()-starttime
report_search_time(tests, seconds)
return result
I interpret your question to mean that you want to interlace the numeric guesses with the alphabetic guesses.
One problem you are facing is that the logic that keeps time and the logic that checks if the password is correct is mixed in with the logic that generates guesses. You might want to use generators to break out the "guess generation" into separate functions.
from itertools import izip
def numerical_guess():
current_guess = 0
while True:
yield current_guess
current_guess += 1
def dictionary_guess():
for word in {'apple', 'banana', 'orange'}:
yield word
for guess in izip(numerical_guess(), dictionary_guess()):
if guess == password:
print "Got it!"
else:
print "Not it!"
There are some things you will have to think about, such as what if one generator runs out before the other one.
You mention that you don't know enough to understand this level of code, but I don't see anything so complicated with the code. Your posted code only uses the most basic control structures of python so I wonder if this post will even be helpful for you. Maybe you could go through the code line by line and mention any part of the code that is confusing for you.

Categories