How can I do this specific replacement - python

string = input("Enter a string:")
character = input ("Enter a character:")
if character in string: #checks string to see if character is in it
print ("Character found!")
else:
print ("Character not found!")
blank = (" _ " * len(string))
print (blank)
I am making a hangman game and I am stuck at this part.
How can I make it so that when the person guesses a letter it replaces the specific " _ " for where the letter should be? Should I be using a for loop to go through all the " _ " 's and then use an if statement?
If someone could show me how it would be great.

You can use a method similar to the following to update your guess string each time the player guesses something.
def update_guesses(current_guess_string, key_string, character_guessed):
out_string = ""
for i in range(len(current_guess_string)):
if current_guess_string[i] == "_" and key_string[i] == character_guessed):
out_string += character_guessed
else: out_string += current_guess_string[i]
return out_string

Building on your code, here's a set of changes that get you to a working game:
Set your string input to a fixed case and move your blank initialization to just after string input. Change them both to lists so you can modify
them as needed:
# normalize case and convert to a mutable data structure
string = list(input("Enter a string: ").lower())
# the blank list matches the string except it starts all blanks
blank = list("_" * len(string))
Get a loop going for handling guesses. Here I'm stopping the loop when the string list is all one character, presumably blanks, as we'll be swapping characters between the blank and input string lists:
while len(set(string)) > 1: # when the string is all blanks, stop
Make sure to cleanup the user input to be only one character and change it to the same case as the string input:
# normalize case on input and make sure to only get 1 character
character = input("Enter a character: ").lower()[0]
After you test if the character is in the string, swap the character, by position, with a character in the blank string. Do this in a loop so you get all instances of the guessed character:
if character in string: # checks string to see if character is in it
print("Character found!")
# find the character in the string and swap it with what's in
# the blank string so we can handle multiple same characters
# correctly
while character in string:
index = string.index(character)
string[index] = blank[index]
blank[index] = character
else:
print("Character not found!")
The last step in the main loop is to print the current state of the guesses:
# print correct guesses and blanks
print(*blank, sep='')

Related

Outputs printed on same line - python

message = str(input())
for i in message:
if i == " ":
print(" ")
else:
# ord(i) returns the ASCII number for i
# To get the actual alphabetical position of i, you have to do ASCII of letter - ASCII of A + 1.
print(ord(i)-ord("a")+1)
This program converts each character of the users input to a letter, based on their alphabetical order (a = 1, b = 2, ect) and prints each number output on a new line. How do I get change this so that when each number is printed, it is on the same line as the last? (eg 123)
Set the optional end argument to "" in print() as:
print(ord(i)-ord("a")+1, end="")
Use this
print("what ever you want to print",end= " ")
It will print without taking the cursor down a line.

How do you split duplicate letters with "x" in Python?

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)

Additional letter printed when I am executing Decode()

So when I encode "hello" in my Encode() function, with a shift of three I get the result "khoor". When I attempt to decode "khoor" using my decode function with a shift of three, I get "hellor". This is strange because an extra letter "r" is returned, despite only decoding 5 letters. This happens with every string I attempt to decode, and I have noticed that the last letter of every string to be encoded is added as an additional letter to the decoded string.
ALPHABET = 'abcdefghijklmnopqrstuvwxyz'
def Menu():
print("Please choose from the following: \n")
print("'e' to encode a string.")
print("'d' to decode a string.")
print("'q' to quit.\n")
choice = input("Please enter one of the letters above.\n")
if choice == "e":
print (Encode())
if choice == "d":
print (Decode())
if choice == "q":
print("The program will now exit.")
quit()
def stringValidation():
while True:
try:
valid = str(input("Enter a string to encode.\n"))
return valid
break
except:
print("Value Error. Enter a string with only letters from the alphabet.")
continue
def shiftValidation():
while True:
try:
valid = int(input("Enter the number of shifts you would like.\n"))
return valid
break
except:
print("Value Error. Please enter an integer.")
def decodeShiftValidation():
while True:
try:
valid = int(input("Enter the key. (Number of shifts used to encrypt the encoded word.)\n"))
return valid
break
except:
print("Value Error. Please enter an integer.")
def Encode():
data = []
string = stringValidation() # asks the user for the string input to be encoded
shift = shiftValidation() # asks the user for the number of shifts
for i in string: # for the letters in string...
if i.strip() and i in ALPHABET: # i.strip removes all default whitespace characters from i (string input by user.)
data.append(ALPHABET[(ALPHABET.index(i) + shift) % 26]) # gets position of the letters from input string in ALPHABET using indexing, and adds the shift to get the new position and new letter.
else:
data.append(i) # if it is a space, simply append it to the data.
output = ''.join(data)
return output
encoded_string= Encode()
print(encoded_string)
def Decode():
data = []
string = input("Please enter the string you wish to decode.\n")
shift = int(input("Enter the key. (Number of shifts used when encoding original word. \n"))
for i in string:
if i.strip() and i in ALPHABET:
data.append(ALPHABET[(ALPHABET.index(i) - shift) % 26])
else:
data.append(i)
output = ''.join(data)
return output
Menu()
An indentation error makes the else of your Decode function a else for the for loop (which is a lesser-known feature of for loop: if no break is encountered, the else executes, adding an extra letter in your case).
That explains why you don't get an error but unexpected behaviour.
More here: Why does python use 'else' after for and while loops?
Aside, a very clumsy way to search in the alphabet is to use index, when you can compute the index directly with characters codes:
data.append(ALPHABET[(ord(i)-ord(ALPHABET[0]) + shift) % 26])
Aside #2: note that decode & encode methods are very similar. Factorize them with the shift as parameter (which is the opposite from one method to the other)
I got errors trying to run your script until I changed all of the input statements to raw_input. But I don't quite understand the logic behind if i.strip() and i in ALPHABET:. Also, you don't have to accumulate letters in a list one at a time and then join them back, when Python lets you append strings directly. In any case, when I simplified your Decode() function to the following, it worked for me:
def Decode():
string = raw_input("Please enter the string you wish to decode.\n").lower().strip()
if string.isalpha():
shift = int(raw_input("Enter the key. (Number of shifts used when encoding original word. \n"))
return ''.join([ ALPHABET[(ALPHABET.index(c) - shift) % 26] for c in string])
I also added in a .lower() and .isalpha() check in case the user uses any capital letters or non-alphabetic strings, but there are other things like this you can add to handle other use cases.

Python Programming String Handling Functions

So, I'm a beginner to programming. I am trying to create a program where the user can input a sentence and the program will tell the user how many letters are in that sentence.
counter=0
wrd=raw_input("Please enter a short sentence.")
if wrd.isalpha():
counter=counter+1
print "You have" + str(counter) +"in your sentence."
When I enter this, my output is blank. What is my mistake in this program?
You need to indent code inside if blocks. In the code you have provided, you've forgotten to indent counter = counter + 1.
You are missing a loop across all characters of wrd. Try this instead,
counter = 0
wrd = raw_input("Please enter a short sentence.")
# Iterate over every character in string
for letter in wrd:
# Check if the letter is an alphabet
if letter.isalpha():
# Increment counter only in this condition
counter += 1
print "You have " + str(counter) + " in your sentence."
First of all as #kalpesh mentioned, the statement counter=counter+1 should be indented.
Second of all, you need to iterate over the entire string entered and then count the number of characters or whatever the logic you need.
counter=0
wrd=raw_input("Please enter a short sentence.")
for i in wrd:
if i.isalpha():
counter = counter+1
print "You have " + str(counter) +"in your sentence."
Once you start learning more, then you can use the below code,
counter=[]
count = 0
wrd=raw_input("Please enter a short sentence.")
counter = [len(i) for i in wrd.split() if i.isalpha()]
print "You have " + str(sum(counter)) +"in your sentence."
I am just splitting the word and then checking if it is alpha or not and using the list comprehension to iterate over the string entered.
wrd.isalpha() returns a boolean (true or false). So if the function returns true, counter=counter+1 will be called once (and only once). You need to iterate through every letter of wrd and call isalpha() on each letter.
You could always remove the spaces from your sentence using replace() then use len() to get how many characters are in the sentence.
For example:
sentence = input("Type in a sentence: ") # Ask the user to input a sentence
sentence = sentence.replace(" ", "") # Replace the spaces in the sentence with nothing
print("Your sentence is " + str(len(sentence)) + " characters long") # Use len() to print out number of letters in the sentence

How to replace characters in a string using iteration and variables? (Python)

I am writing a hangman game in python as part of a college project, and I am trying to use string.replace(old, new) to substitute the blanks (_) with letters. Instead of using actual string characters though, I am trying to use variables for 'old' and 'new'. Here's what I've got so far for this bit:
if validGuess == 'true':
if guess in word:
for letter in word:
if letter == guess:
word.replace(letter, guess)
else:
missNum = (missNum + 1)
else:
tryNum = (tryNum - 1)
However, it isn't working. I don't get any errors, it simply will not replace the blanks.
What am I doing wrong here? Is there a better way to achieve what I am doing?
-EDIT-
I tried to implement #Peter Westlake's solution (which seemed to me the most elegant) but I have run into an issue. I have a section of code which converts a randomly selected word into underscores:
#converting word to underscores
wordLength = len(word)
wordLength = (wordLength - 1)
print(wordLength) #testing
for i in range(0,wordLength):
wordGuess = (wordGuess + '_')
print(wordGuess)
And this seems to work fine. Here is the code for letter substitution:
if validGuess == 'true':
wordGuess = ''.join([letter if guess == letter else wordGuess[pos]
for pos, letter in enumerate(word)])
if guess not in word:
tryNum = (tryNum - 1)
print(wordGuess)
However, here is the output:
Guess a letter: a
test
Traceback (most recent call last):
File "G:\Python\Hangman\hangman.py", line 60, in <module>
for pos, letter in enumerate(word)])
File "G:\Python\Hangman\hangman.py", line 60, in <listcomp>
for pos, letter in enumerate(word)])
IndexError: string index out of range
String index out of range? What does that mean?
str.replace() returns the new string, store the new value:
word = word.replace(letter, guess)
Python strings are immutable and cannot be altered in-place.
However, you are replacing letter with the exact same value; letter == guess is only True if both are the same character.
I'd keep a separate set of correctly guessed letters instead, and rebuild the displayed underscores and correct guesses each time:
correct_guesses = set()
incorrect_guesses = set()
if guess in correct_guesses & incorrect_guesses:
print('You already guessed that letter')
elif guess in word:
# correct guess!
correct_guesses.add(guess)
display_word = ''.join(char if char in correct_guesses else '_' for char in word)
else:
# incorrect guess!
incorrect_guesses.add(guess)
print('Oops, incorrect guess!')
missNum += 1
I think I understand what you're getting at here.
I would probably rebuild the word-so-far on the spot instead of having a persistent string for it, keeping the tested letters separately. When the user tries a new character, make two checks:
See if the guess character has been guessed already: if guess in tried. If so, proceed however you like (penalize or ignore), but don't add the character to the tried-characters list.
If not, see if the character is in the target word: elif guess in word. If not, assess some penalty and add the guess to the tried-characters list.
For any other result: else. Add the guess to the tried-characters list.
To display the user's progress, make a blank string. Go through the target word character-at-a-time: for char in word, like you have been. But instead of trying to modify an extant string, just add the character to the end of the blank string if it's in the tried-characters string, or an underscore if not: show += char if char in tried else "_". Once that for loop is exhausted, display what you've got!
Alternatively, use .join with a slightly different iterator: show = "".join(char if char in tried else '_' for char in word). It'll iterate through word, keeping each letter if it's in your tried-characters string, or substituting an underscore if not, putting whatever is in "" between them (or nothing, if you leave it as ""). It looks like you already know that, though.
At the hazard of completely rewriting your code, this is what it might look like:
## init
word = "mauritius" # the word you're looking for. I chose this one.
tried = str() # initialize a list of tested characters
tryNum = 3 # however many wrong guesses the user gets
...
## in your run loop...
if tryNum: # evaluates 0 as Fasle, if you didn't already know
guess = UserInput() # some means to get the guess from the user; a single-character string.
if guess in tried:
print "Tried that letter already!"
elif guess not in word: # the letter hasn't been tested yet, but isn't in the word, either.
print "Wrong! %d guesses left!" % tryNum
tryNum -= 1
tried += guess
else: # the guess is new (not tried) and it's valid (in the word)
tried += guess
show = str() # this is the string you will display. make a blank one each time.
for char in word:
show += char if char in tried else "_" # if the character has been tried, add it to the output. Otherwise, an underscore.
print show # display the word so far
if show == word:
print "You win!" # Congratulations! You hung a man.
else: # Out of tries; the convict lives another day.
print "Game Over!" # I am not sure how committed to this vocabulary-based execution you really are...
You can swap if tryNum: with while tryNum: and it should work all by itself, after initialization. If you do, there are fun things you can do with continues and breaks, but that goes a bit beyond the scope of your question.
You can swap show = str() and the for char in word: block out with the .join singleton in this next example, too. Change ''.join(..) to ' '.join(..) to add a space between characters/underscores!
This compressed version is probably a bit less Pythonic:
# post-init...
if tryNum:
guess = UserInput()
if guess in tried: pass
elif guess not in word:
print "Wrong! %d guesses left!" % tryNum
tryNum -= 1
tried += guess
else: tried += guess
show = ''.join(char if char in tried else '_' for char in word)
if show == word: print "You win!"
else: print "Game Over!"
This does not answer your first question of "What am I doing wrong?" but I think it might be a better way of going about what you intend? It might be a bit easier to maintain and expand for you, too.
Note: Go ahead and replace UserInput() with something like str(raw_input("Guess a letter!"))[0] if you want to try this thing out on its own.
Replacing a letter with an identical guess isn't going to do anything! I think you want to find the position in the word where the guessed letter appears, and replace the _ in that position with the letter. For that you will need to find every position where the letter occurs, e.g. using the index() method.
For instance, to replace the first occurrence of the guess:
# Illustration of the principle, not the complete answer.
word = 'faq'
display = '___'
# Put in a loop, one iteration for each guess input.
guess = 'a'
display = ''.join([letter if guess == letter else display[pos]
for pos, letter in enumerate(word)])
print display
Which will print _a_.

Categories

Resources