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)
Related
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('#', ' ')
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)
I make a function to input string and return with head and tail with two indexes without space and punctuation. but it's return only "empty string"
def hello(word):
str_cnt = ""
for letter in word:
if letter not in string.whitespace and letter not in string.punctuation:
str_cnt += letter
if len(str_cnt) < 2 :
return "empty string"
else:
return str_cnt[:2] + str_cnt[-2:]
word = input("Input String : ")
result = hello(word)
print("Result: ",result)
I expect when I input "hello world!", and the actual output is "held"
or "Hi!" = "HiHi".
The problem is simply incorrect indentation:
import string
def hello(word):
str_cnt = ""
for letter in word:
if letter not in string.whitespace and letter not in string.punctuation:
str_cnt += letter
if len(str_cnt) < 2:
return "empty string"
return str_cnt[:2] + str_cnt[-2:]
word = input("Input String: ")
result = hello(word)
print("Result: ", result)
Indentation is everything in Python!
> python3 test.py
Input String: hello world!
Result: held
>
However, if the input is long, this is the wrong way to go about the problem. We test a lot of characters we'll never use against the whitespace and punctuation lists. Instead we should grab the first two valid characters from either end of the list and ignore the middle. Something like:
def hello(word):
unwanted = string.whitespace + string.punctuation
str_start = ""
for letter in word:
if letter not in unwanted:
str_start += letter
if len(str_start) == 2:
break
if len(str_start) < 2:
return "empty string"
str_end = ""
for idx in range(len(word) - 1, -1, -1):
if word[idx] not in unwanted:
str_end = word[idx] + str_end
if len(str_end) == 2:
break
return str_start + str_end
EXAMPLE
> python3 test2.py
Input String: telecommunications!
Result: tens
>
The letters 'lecommunicatio' were never tested as they had no effect on the eventual outcome.
You miss-indented the last if block:
import string
def hello(word):
str_cnt = ""
for letter in word:
if letter not in string.whitespace and letter not in string.punctuation:
str_cnt += letter
if len(str_cnt) < 2 :
return "empty string"
else:
return str_cnt[:2] + str_cnt[-2:]
word = input("Input String : ")
result = hello(word)
print("Result: ",result)
Example output:
Input String : Hello World!
Result: Held
Your issue is that you return after the first iteration through the work, no matter what.
Move the return nogic after the logic:
def hello(word):
str_cnt = ""
for letter in word:
if letter not in string.whitespace and letter not in string.punctuation:
str_cnt += letter
if len(str_cnt) < 2 :
return "empty string"
else:
return str_cnt[:2] + str_cnt[-2:]
The problem is indentation as everyone says, after correcting which it works. I would do it more pythonically as:
def hello(word):
w = ''.join([x for x in word if x not in string.whitespace and x not in string.punctuation])
return w[:2] + w[-2:] if len(w) > 1 else 'empty string'
Usage:
>>> hello('hello world!')
held
I have two functions that convert between katakana and hiragana and they look the same:
katakana_minus_hiragana = 0x30a1 - 0x3041 # KATAKANA LETTER A - HIRAGANA A
def is_hirgana(char):
return 0x3040 < ord(char[0]) and ord(char[0]) < 0x3097
def is_katakana(char):
return 0x30a0 < ord(char[0]) and ord(char[0]) < 0x30f7
def hiragana_to_katakana(hiragana_text):
katakana_text = ""
max_len = 0
for i, char in enumerate(hiragana_text):
if is_hirgana(char):
katakana_text += chr(ord(char) + katakana_minus_hiragana)
max_len += 1
else:
break
return katakana_text, max_len
def katakana_to_hiragana(katakana_text):
hiragana_text = ""
max_len = 0
for i, char in enumerate(katakana_text):
if is_katakana(char):
hiragana_text += chr(ord(char) - katakana_minus_hiragana)
max_len += 1
else:
break
return hiragana_text, max_len
Is there a way to simplify hiragana_to_katakana() and katakana_to_hiragana() into a duck-type function or a super/meta function?
E.g. something like
def convert_hk_kh(text, charset_range, offset):
charset_start, charset_end = charset_range
output_text = ""
max_len = 0
for i, char in enumerate(text):
if charset_start < ord(char[0]) and ord(char[0]) < charset_end:
output_text += chr(ord(char) + offset)
max_len +=1
else:
break
return output_text, max_len
def katakana_to_hiragana(katakana_text):
return convert_hk_kh(katakana_text, (0x30a0, 0x30f7), -katakana_minus_hiragana)
def hiragana_to_katakana(hiragana_text):
return convert_hk_kh(hiragana_text, (0x3040, 0x3097), katakana_minus_hiragana)
Are there other pythonic ways to simplify the two functions that are very similar?
EDITED
There's also https://github.com/olsgaard/Japanese_nlp_scripts which seems to do the same thing with str.translate. Is that more efficient? More pythonic?
I'd do something like this:
KATAKANA_HIRGANA_SHIFT = 0x30a1 - 0x3041 # KATAKANA LETTER A - HIRAGANA A
def shift_chars_prefix(text, amount, condition):
output = ''
for last_index, char in enumerate(text):
if not condition(char):
break
output += chr(ord(char) + amount)
return output, last_index
def katakana_to_hiragana(text):
return shift_chars_prefix(text, -KATAKANA_HIRGANA_SHIFT, lambda c: '\u30a0' < c < '\u30f7')
def hiragana_to_katakana(text):
return shift_chars_prefix(text, KATAKANA_HIRGANA_SHIFT, lambda c: '\u3040' < c < '\u3097')
You can also use regex if you don't return the length of the replaced prefix:
import re
KATAKANA_HIRGANA_SHIFT = 0x30a1 - 0x3041 # KATAKANA LETTER A - HIRAGANA A
def shift_by(n):
def replacer(match):
return ''.join(chr(ord(c) + n) for c in match.group(0))
return replacer
def katakana_to_hiragana(text):
return re.sub(r'^[\u30a1-\u30f6]+', shift_by(KATAKANA_HIRGANA_SHIFT), text)
def hiragana_to_katakana(text):
return re.sub(r'^[\u3041-\u3096]+', shift_by(-KATAKANA_HIRGANA_SHIFT), text)
Here’s a function that would switch each kind of kana to the other.
Unlike the given functions, it does not stop when it encounters
non-kana, but simply passes those characters through without changing
them.
Note that conversion between kana types is not as simple as this; for
example, in hiragana a long “e” sound is indicated by ええ or えい
(e.g., おねえ older sister, せんせい teacher), while in katakana one
uses a chōonpu (オネー, せんせー). There are kana characters outside the
ranges you use as well.
def switch_kana_type(kana_text):
"""Replace each kind of kana with the other kind. Other characters are
passed through unchanged."""
output_text = ''
for c in kana_text:
if is_hiragana(c): # Note typo fix of "is_hirgana"
output_text += chr(ord(c) + katakana_minus_hiragana)
elif is_katakana(char):
output_text += chr(ord(c) - katakana_minus_hiragana)
else:
output_text += c;
return output_text, len(output_text)
I have a function to test whether a string is palindrome or not:
def palindrome(raw_text):
# first to convert raw_text to a string of lower case letters and remove the space
text = raw_text.lower()
text = text.replace(' ', '')
print('text is now', text)
print('length of text is', len(text))
if len(text) == 1 or len(text) == 0:
return True
else:
if text[0] == text[-1]:
print('so far so good')
palindrome(text[1:-1])
else:
return False
To make it clear for debug, I added a few print command to help me.
if I try:
raw_text = 'abcba'
print(palindrome(raw_text))
I will get:
text is now abcba
length of text is 5
so far so good
text is now bcb
length of text is 3
so far so good
text is now c
length of text is 1
None
So why am I getting a None at the end? I did have the return True command for len(text) == 1 or 0
If I just give raw_text = 'a', it will give me:
text is now a
length of text is 1
True
You forgot to recurse properly.
return palindrome(text[1:-1])
Thanks, as #Ignacio Vazquez-Abrams mentioned, I did not recurse properly.
Actually the code does not need to be this complicate.
I have revised it to:
def palindrome(raw_text):
# first to convert raw_text to a string of lower case letters and remove the space
text = raw_text.lower()
text = text.replace(' ', '')
print('text is now', text)
print('length of text is', len(text))
if len(text) <= 3:
return text[0] == text[-1]
else:
return text[0] == text[-1] and palindrome(text[1:-1])