trying to decode # into whitespace - python

origAlpha = string.ascii_lowercase + string.ascii_uppercase + string.digits + string.punctuation + ''
shift = int(input("what shift do you want to use to decode? "))
shiftAlpha = origAlpha[shift : ] + origAlpha[ : shift]
messageToDecode = 'k#nkmg#rtqitcookpi'
decodedMessage = ""
count = 0
while count < len(messageToDecode):
nextLetter = messageToDecode[count]
if(nextLetter=='#'):
decodedMessage += ' '
elif nextLetter.isalpha():
index = shiftAlpha.index(nextLetter)
nextLetter = origAlpha[index]
decodedMessage += nextLetter
count += 1
im trying to decode the # into whitespaces but its not working and cant seem to figure out the error can someone help- shift is 2 - i get this answer 'i#like#programming' when i want it 'i like pogramming'

Note that you're including digits and punctuation in your origAlpha and shiftAlpha, even though you're checking for nextLetter.isalpha(), and digits and punctuation aren't alphabetic characters. That said, you unconditionally add nextLetter to decodedMessage. To make sure no # characters get added, you can do something like this:
nextLetter = messageToDecode[count]
if nextLetter == '#':
nextLetter = ' '
elif nextLetter.isalpha():
index = shiftAlpha.index(nextLetter)
nextLetter = origAlpha[index]
decodedMessage += nextLetter
Bonus:
Instead of using origAlpha and shiftAlpha to find a string in linear time, consider using a dictionary, and instead of using a while loop, consider using a for loop. You can get something like this:
origAlpha = string.ascii_lowercase + string.ascii_uppercase + string.digits + string.punctuation
shift = int(input("what shift do you want to use to decode? "))
shiftAlpha = origAlpha[shift:] + origAlpha[:shift]
mapping_characters = dict(zip(shiftAlpha, origAlpha))
mapping_characters['#'] = ' '
message_to_decode = 'k#nkmg#rtqitcookpi'
decoded_message = ""
for letter in message_to_decode:
decoded_message += mapping_characters.get(letter, letter)

I might be missing something but can you just use:
message = 'k#nkmg#rtqitcookpi'
decoded = message.replace('#', ' ')

Related

str.replace(last_letter, second_letter) and replace(second_letter, last_letter) resulting in only one of them executing

In the following Python code where I am deciphering a message that should theoretically result in Ready, set go output the two lines with str.replace() are obviously not executing as expected, resulting in only the second character of the word being replaced:
# Input:
# 82yade 115te 103o
#
# Output:
# Ready set go
user_input = input().split(" ")
first_letter = ''
second_letter = ''
last_letter = ''
printable_list = []
ord_char = ''
final_str = ''
concat_str = ''
for word in user_input:
final_str = ''
first_letter = ''
last_letter = ''
ord_char = ''
concat_str = ''
for idx in range(0, len(word)):
if word[idx].isdigit():
first_letter = word[idx]
ord_char += first_letter
else:
final_str += word[idx]
concat_str = chr(int(ord_char)) + final_str
second_letter = concat_str[1]
last_letter = concat_str[len(concat_str) - 1]
print(second_letter, last_letter) # this prints here only for debugging purposes, e.g. to check 2nd and last letter
concat_str = concat_str.replace(last_letter, second_letter)
concat_str = concat_str.replace(second_letter, last_letter)
printable_list.append(concat_str)
print(' '.join(printable_list))
Hence, what I expect to come out as "Ready set go" is "Reade see go". What is causing the second replace to malfunction?
What I tried to achieve is that the second and the last letter are switched (e.g., Holle means Hello) and that the first letter is replaced by its character code (e.g., 72 means H) which runs smoothly until I hit the line replacing the 2nd with my last character of each of the words I add to the printable_list.
Consider the string:
Ryade
If you replace the last_letter (e) with the second_letter (y) you get:
Ryady
Now if you replace second_letter (y) with last_letter (e) you get:
Reade
All of the y's were replaced with e's.
To get around this issue you can introduce a placeholder character (as one of many options):
placeholder = '^'
concat_str = concat_str.replace(last_letter, placeholder)
concat_str = concat_str.replace(second_letter, last_letter)
concat_str = concat_str.replace(placeholder, second_letter)
With this logic our input of Ryade will take the following steps:
Ryed^
Read^
Ready
From my comment below, you may have better success being more tactical about which character you are replacing by using its position in the word (after swapping out that first letter). There are likely prettier ways to do this, but this feels like a reasonable direction:
import re
user_input = input().split(" ")
printable_list = []
for word in user_input:
word = word.replace(re.findall('^[0-9]*', word)[0], chr(int(re.findall('^[0-9]*', word)[0])))
if len(word) > 2:
word = word[0] + word[len(word) - 1] + word[2:len(word)-1] + word[1]
printable_list.append(word)
print(' '.join(printable_list))
str.replace is based on old and new substrings, irrespective of positions.
str.replace(old, new[, count])
Return a copy of the string with all occurrences of substring old replaced by new. If the optional argument count is given, only the first count occurrences are replaced.
You can use f-strings to replace characters at specific positions:
first_letter = concat_str[0]
second_letter = concat_str[1]
third_to_second_last_letter = concat_str[2:-1]
last_letter = concat_str[-1]
# concat_str = concat_str.replace(last_letter, second_letter)
# concat_str = concat_str.replace(second_letter, last_letter)
if len(concat_str) > 2:
concat_str = f'{first_letter}{last_letter}{third_to_second_last_letter}{second_letter}'
A less performant but more obvious swap, using a list of characters since str is immutable:
second_letter = concat_str[1]
last_letter = concat_str[-1]
# concat_str = concat_str.replace(last_letter, second_letter)
# concat_str = concat_str.replace(second_letter, last_letter)
concat_str_list = list(concat_str)
concat_str_list[1], concat_str_list[-1] = last_letter, second_letter
concat_str = ''.join(concat_str_list)

How can spaces be ignored in the input, but printed at the end?

I need to count how many times the same character is repeated and then use that count as an offset in ASCII. For example: ** * should give B A. Because 2 *s mean B (the second letter) and 1 * means A (the first letter).
My problem is that spaces are considered as a character and translated as A. How can I ignore spaces in the input, but include them in my print statement? I currently get BAA instead. This is my code:
def main():
encrypted = "** *"
#input("Enter an encrypted message: ")
count = 0
decoded = ''
for i, ch in enumerate(encrypted):
if i == 0 or ch == encrypted[i-1]:
count += 1
else:
decoded += chr(count + 64)
count = 1
if count > 0:
decoded += chr(count + 64)
print(decoded)
main()
Another example: the input:
********bbbbb&&&&&&&&&&&&999999999999zzzzzzzzzzzzzzz ********bbbbb&&&&&&&&&&&&999999999999zzzzzzzzzzzzzzz
should print out HELLO HELLO.
To solve your problem with minimal changes, you can just add a special check for the space:
...
for i, ch in enumerate(encrypted):
if encrypted[i-1] == ' ':
decoded += ' '
elif i == 0 or ch == encrypted[i - 1]:
...
But you can opt for a simpler way by using groupby:
from itertools import groupby
def main():
encrypted = "** *"
# input("Enter an encrypted message: ")
decoded = ""
for key, group in groupby(encrypted):
if key == ' ':
decoded += ' '
else:
decoded += chr(sum(1 for _ in group) + 64)
print(decoded)
main()
how about a little different approach? Every char is seperated by a space, so just split the input to a list and check the length of each char.
Like this:
def main():
encrypted = "** *"
#input("Enter an encrypted message: ")
count = 0
inp_list= encrypted.split(' ')
decoded = [chr(len(elem) + 64) for elem in inp_list]
for ch in decoded:
print(ch, end=' ')
main()
Output: B A
I like the approach by Tomerikoo, though this is a different approach using what you've already written.
Since your code works without spaces, just run it once per word and join the result together.
def decode_word(word):
decoded = ''
count = 0
for i, ch in enumerate(word):
if i == 0 or ch == word[i-1]:
count += 1
else:
decoded += chr(count + 64)
count = 1
if count > 0:
decoded += chr(count + 64)
return decoded
def decode_string(encrypted):
return ' '.join(map(decode_word, encrypted.split()))
print(decode_string("** *"))
# B A
print(decode_string("********bbbbb&&&&&&&&&&&&999999999999zzzzzzzzzzzzzzz ********bbbbb&&&&&&&&&&&&999999999999zzzzzzzzzzzzzzz"))
# HELLO HELLO

Function: fill the string to get a length

So I am trying to create a function that recives 3 parameters, a string a number and a char.
If the len(string) is not the same as the number given, I want to fulfill the string with the given char.
I tried doin' this, but didn't work. Where do I miss?
def expand(text, length, char):
new_text = ""
if length <= len(text):
print(text)
else:
diff = length - len(text)
if diff % 2 == 0:
len(new_text) == length
new_text = char + text + char
else:
len(new_text) == length
new_text = char + text + char
new_text = char + text
print(new_text)
I mean how could I create a condition that helps me to add as many "char" I need but in the same time checks if len(text) is the same with the number given? If you could explain me where should I look and how do I have to think about the problem, it would be awesome. I just want to understand the way, not just to have the answer. Thank you!
You can use this approach where multiplying a char by a number will give you a string of that length. eg. 'a' * 3 = 'aaa'
def expand(text, length, char):
new_text = ""
if length <= len(text):
new_text = text
else:
diff = length - len(text)
if diff % 2 == 0:
new_text = char*int(diff/2) + text + char*int(diff/2)
# length of text is automatically updated
else:
new_text = char*int((diff-1)/2) + text + char*int((diff-1)/2)
new_text = char + new_text
print(new_text)
return new_text
You could use a while to add the character until the string reaches the desired length:
new_text = text
while len(text) < length:
if len(text)%2 == 0:
new_text = new_text + char
else
new_text = char + new_text
If you want to generate a certain number of repeating characters, you can multiply the character by a number. e.g. "A"*3 --> "AAA"
So you could approach it like this:
padLeft = (length-len(text))//2
padRight = length-len(text)-padLeft
return char*padLeft + text + char*padRight
There's also the recursive approach:
def expand(text, length, char):
if len(text)>=length: return text
if len(text)%1: return expand(text+char,length,char)
else: return expand(char+text,length,char)

i there a way to rewrite the code?,i can not seem to get it right, i can not seem to get the input correctly

I have to edit the code i previously wrote to make it work with a input, I will attach the problem. I can not seem to get it to work.
it has to be some sort of input,
string =" "
reversed_string = string[::-1]
result_string = " ".join(string)
for a in range (0 ,3):
result_string += chr(ord('a')+a)
for a in range(0 , 2)[::-1]:
result_string += chr(ord('a')+a)
print result_string
string =" "
add this to input from keyboard
input( 'type a letter from a to z')
This is the shortest I could make the answer
character = 97
char_list = []
con = True
a = 0
for interger in range(26):
char = chr(character)
char_list.append(char)
character = character+1
get_char = input("Enter a letter from a-z")
while con == True:
if get_char == char_list[a]:
b = char_list[:a+1]
char_list.reverse()
print(b+char_list[-a:])
con = False
else:
a = a+1

implement my own strip method in Python

I am trying to implement my own strip method in Python, so without using the built-in method, I'd like my function to strip out all the whitespace from the left and the right.
Here, what I am trying to do is create a list, remove all the blank character before the first non-space character, then do it reverse way, finally return the list to a string. But with what I wrote, it doesn't even remove one whitespace.
I know what I am trying to do might not even work, so I would also like to see the best way to do this. I am really new to programming, so I would take any piece of advise that makes my program better. Thanks!
# main function
inputString = input("Enter here: ")
print(my_strip(inputString))
def my_strip(inputString):
newString = []
for ch in inputString:
newString.append(ch)
print(newString)
i = 0
while i < len(newString):
if i == " ":
del newString[i]
elif i != " ":
return newString
i += 1
print(newString)
Instead of doing a bunch of string operations, let's just get the beginning and ending indices of the non-whitespace portion and return a string slice.
def strip_2(s):
start = 0
end = -1
while s[start].isspace():
start += 1
while s[end].isspace():
end -= 1
end += 1
return s[start:end or None]
How about using regular expression?
import re
def my_strip(s):
return re.sub(r'\s+$', '', re.sub(r'^\s+', '', s))
>>> my_strip(' a c d ')
'a c d'
What you seem to be doing is an ltrim for spaces, since you return from the function when you get a non-space character.
Some changes are needed:
# main function
inputString = input("Enter here: ")
print(my_strip(inputString))
def my_strip(inputString):
newString = []
for ch in inputString:
newString.append(ch)
print(newString)
i = 0
while i < len(newString):
if i == " ": # <== this should be newString[i] == " "
del newString[i]
elif i != " ": # <== this should be newString[i] == " "
return newString
i += 1 # <== this is not needed as the char is deleted, so the next char has the same index
print(newString)
So the updated code will be:
# main function
inputString = input("Enter here: ")
print(my_strip(inputString))
def my_strip(inputString):
newString = []
for ch in inputString:
newString.append(ch)
print(newString)
i = 0
while i < len(newString):
if newString[i] == " ":
del newString[i]
elif newString[i] != " ":
return newString
print(newString)
Good luck with the rest of the exercise (implementation of rtrim).

Categories

Resources