I don't know why but the code I wrote isn't running. I'm trying to generate a random index and deleting it from the string. It's not giving me an error message so I don't know what's wrong. Here's what I have:
def delete_randomly(string):
i = 0
while i < len(string):
if string[i] == randint(0, 10):
return string.remove(string[i])
This infinite loop will never break depending on the input. Is this what you trying to achieve?
from random import randint
def delete_randomly(string):
print(f'input string = {string}')
ran_int = randint(0, len(string))
print(f'removing index = ({ran_int})')
new_str = ''
for idx, val in enumerate(string):
if idx == ran_int:
continue
new_str+=val
return new_str
print(delete_randomly('abakdkemnaskakac'))
As an addition for #Juan Antonio Martinez Lopez answer's, you could also use the following code:
def delete_randomly(string):
randomIndex = randint(0, len(string) - 1)
return string[:randomIndex] + string[randomIndex + 1:]
You are in an infinite loop. Imagine the string is 'stackoverflow', your code is always comparing string[0] (because i == 0 everytime) with a random number between 0-10. For example
First iteration:
string[0] = 's'
randint(0, 10) = 3
Second iteration:
string[0] = 's'
randint(0, 10) = 7
Infinite iteration
string[0] = 's'
randint(0, 10) = number
Never 's' would be equals to number.
It is also wrong because string class in python has no method named remove.
So if you want remove a valid letter the code is:
def delete_randomly(string):
temp = list(string)
temp[randint(0, len(string) - 1)] = ""
return "".join(temp)
Related
I am trying to take a string from user input like ("what is 1 + 1") separate the letters from numbers and then add the 2 numbers. I have tried the below code buti still cant fiqure out how to add the two 1s.
def splitString(str):
alpha = ""
num = ""
special = ""
for i in range(len(str)):
if(str[i].isdigit()):
num = num+ str[i]
elif((str[i] >= 'A' and str[i] <= 'Z') or
(str[i] >= 'a' and str[i] <= 'z')):
alpha += str[i]
else:
special += str[i]
print(alpha)
print(num )
print(special)
if name == "main":
str = "what is 1 + 1"
splitString(str)
my_str = "what is 1 + 1"
x = []
str_list = my_str.split(" ")
for i in str_list:
if i.isDigit():
x.append(int(i))
sum_integers = 0
for i in x:
sum_integers += i
print(sum_integers)
try this, I did not run it.
The ".split" function will simplify your code a lot.
I encourage you to look at this link https://www.w3schools.com/python/ref_string_split.asp
I might suggest using itertools.groupby as a starting point, e.g.:
>>> import itertools
>>> def split_alpha_num(s: str) -> list[str]:
... return ["".join(g).strip() for _, g in itertools.groupby(s, lambda s:(s.isalpha(), s.isdecimal()))]
...
>>> split_alpha_num("what is 1 + 1")
['what', '', 'is', '', '1', '+', '1']
From there, you could iterate over the string, discard elements that aren't either numbers or mathematical operators, and try to do something with what remains. The exact approach depends on the complexity of the inputs that you want your code to be able to handle; solving this type of problem in the very general case is not trivial.
you should make the variable num a list, and then add to that list all of the numbers
like that
def splitString(str):
alpha = ""
num = []
special = ""
for i in range(len(str)):
if(str[i].isdigit()):
num.append(int(str[i]))
elif((str[i] >= 'A' and str[i] <= 'Z') or
(str[i] >= 'a' and str[i] <= 'z')):
alpha += str[i]
else:
special += str[i]
print(alpha)
print(num)
print(special)
that way later you could use the special variable to determine what to do with thous numbers
My goal is to write a function which change every even letter into upper letter and odd to lower (space also count as a one element).
This is my code
def to_weird_case(s):
for i in s:
if len(i) % 2 == 0:
s[i] = i.upper() + s(i+1)
else:
s[i] = i.lower() + s(i+2)
return i
I think it should be quite correct, but it gives me error.
line 7, in to_weird_case
s[i] = i.lower() + s(str(i)+2)
TypeError: must be str, not int
EDIT:
I have a sugesstion but I don't know how to make it. I try it for myself and back here.
This needs to definitly explicietly state that the zero indexing uppercase is for each word.
Do you know guys how to make it?
So we can analyze your code and just explain what you typed:
def to_weird_case(s):
for i in s: # s is your string, and i is the actual character
if len(i) % 2 == 0: # if your length of the character can be divided by 2. Hmm this is weird
s[i] = i.upper() + s(i+1) # s[i] change a character in the string but you should provide an index (i) so an integer and not a character. But this is not supported in Python.
else:
s[i] = i.lower() + s(i+2)
return i # This will exit after first iteraction, so to_weird_case("this") will return "t".
So what you need to is first create a output string and fill that. And when iteration over s, you want the index of the char and the char value itself.
def to_weird_case(s):
output = ""
for i, myChar in enumerate(s):
if i % 2 == 0:
output += myChar.upper()
else:
output += myChar.lower()
return output
my_sentence = "abcdef"
print(to_weird_case(my_sentence))
And when you want to ignore spaces, you need to keep track of actual characters (excluding spaces)
def to_weird_case(s):
output = ""
count = 0
for myChar in s:
if myChar.isspace():
output += myChar
else:
if count % 2 == 0:
output += myChar.upper()
else:
output += myChar.lower()
count += 1
return output
my_sentence = "abc def"
print(to_weird_case(my_sentence))
Test this yourself
def to_weird_case(s):
for i in s:
print (i)
After doing this you will find that i gives you characters.
if len(i) % 2 == 0:
This line is incorrect as you are trying to find the length of a single character. len(s) would be much better.
So the code will be like
def to_weird_case(s):
s2 = "" #We create another string as strings are immutable in python
for i in range(len(s)):
if i % 2 == 0:
s2 = s2 + s[i].upper()
else:
s2 = s2 + s[i].lower()
return s2
From #RvdK analysis, you'ld have seen where corrections are needed. In addition to what has been pointed out, I want you to note that s[i] will work fine only if i is an integer, but in your case where (by assumption) i is a string you'll encounter several TypeErrors. From my understanding of what you want to do, it should go this way:
def to_weird_case(s):
for i in s:
if s.index(i) % 2 == 0:
s[s.index(i)] = i.upper() + s[s.index(i)]
elif s.index(i) % 2 == 1:
s[s.index(i)] = i.lower() + s[s.index(i)]
return i # or possibly return s
It is possible to do in a single line using a list comprehension
def funny_case(s):
return "".join([c.upper() if idx%2==0 else c.lower() for idx,c in enumerate(s)])
If you want to treat each word separately then you can split it up in to a list of words and "funny case" each word individually, see below code
original = "hello world"
def funny_case(s):
return "".join([c.upper() if idx%2==0 else c.lower() for idx,c in enumerate(s) ])
def funny_case_by_word(s):
return " ".join((funny_case(word) for word in s.split()))
print(funny_case_by_word(original))
Corrected code is as follows
def case(s):
txt=''
for i in range(len(s)):
if i%2==0:
txt+=s[i].upper()
else:
txt+=s[i].lower()
return txt
String assignment gives error in Python therefore i recommend considering my approach
When looping over elements of s, you get the letter itself, not its index. You can use enumerate to get both index and letter.
def to_weird_case(s):
result = ''
for index, letter in enumerate(s):
if index % 2 == 0:
result += letter.upper()
else:
result += letter.lower()
return result
correct code:
def to_weird_case(s):
str2 = ""
s.split() # through splitting string is converted to list as it is easy to traverse through list
for i in range(0,len(s)):
n = s[i] # storing value in n
if(i % 2 == 0):
str2 = str2 + n.upper()
else:
str2 = str2 + n.lower()
return str2
str1 = "hello world"
r = to_weird_case(str1)
print(r)
OLD MACDONALD: Write a function that capitalizes the first and fourth letters of a name
I'm trying to write this in different ways and I also feel like there's an easier way to do this. Cant, you directly apply it without getting all the other words of a string? Or a split or something?
Here is one of my attempts at trying it another way. I'm trying to do it with a for AND an if statement too. Any help is appreciated.
def old_macdonald(words):
wordletter = words[0]
fourthletter = words[3]
newword = []
for i,l in enumerate(words):
if i[0]:
newword = l.capatalize
return newword
if i[3]:
newword = l.capatalize
return newword
This is the most legible way IMO
def old_macdonald(name):
mylist = list(name)
mylist[0] = mylist[0].upper()
mylist[3] = mylist[3].upper()
return ''.join(mylist)
def old_macdonald(name):
letters = list(name)
for index in range(len(name)):
if index == 0:
letters[index] = letters[index].upper()
elif index == 3:
letters[index] = letters[index].upper()
return "".join(letters)
This one worked for me
this code will make first and forth element of the string Capital.
def cap(name):
first = name[0]
mid = name[1:3]
second = name[3]
rest = name[4:]
return first.upper() + mid + second.upper() + rest
cap('kahasdfn')
Here's one way. You do need to split the string into a list of characters to change individual characters, because strings are immutable, and then use join afterward to convert them back into a string.
def old_macdonald(name):
letters = list(name)
for letter_to_capitalize in [1, 4]:
if len(letters) >= letter_to_capitalize:
letters[letter_to_capitalize - 1] = letters[letter_to_capitalize - 1].upper()
return "".join(letters)
A pretty simple and modifiable example.
def old_mcdonald(word):
indexes = (0,3) #letters i want to cap
new_word = "".join([v.capitalize() if i in indexes else v for i,v in enumerate(word)])
return new_word
def old_macdonald(s):
return ''.join([s[:1].upper(), s[1:3], s[3:4].upper(), s[4:]])
# s[:1] - letter index 0 (first)
# s[1:3] - letters index 1-2
# s[3:4] - letter index 3 (fourth)
# s[4:] - letters index 4 onward
test_string = "abcdefghijklmnopqr"
print(old_macdonald(test_string )) # AbcDefghijklmnopqr
I like writing it this way:
def old_macdonald(word):
indices = (0, 4)
return ''.join(c.capitalize() if index in indices else c for index, c in enumerate(word))
Although it's a little long, so you might prefer writing it more clearly as:
def old_macdonald(word):
indices = (0, 4)
new_string = []
for index, c in enumerate(word):
new_string.append(c.capitalize() if index in indices else c)
return ''.join(new_string)
def old_macdonald(s):
w=""
for i in s:
t=s.index(i)
if t==0:
w=w+i.upper()
elif(t==3):
w=w+i.upper()
else:
w=w+i
print(w)
old_macdonald("aman")
def old_macdonald(s):
return s[0:3].capitalize() + s[3:].capitalize()
https://ideone.com/2D0qbZ
This one worked
def old_macdonald(name):
word = ''
for index,letter in enumerate(name):
if index == 0 or index == 3:
letter = name[index].capitalize()
word += letter
else:
word += letter
return word
Is there a Function in Python to easily create a circular Alphabet, so that the letter after z is a and the letter before a is z?
I tried something with chr() and .join(Alphabet), but that didn't worked because i got the error message an integer is required (got type str).
for character in word:
if chr(Alphabet[Alphabet.find(character)) >= "z":
new_Alphabet = Alphabet.join(Alphabet)
elif chr(Alphabet[Alphabet.find(character)) <= "a":
new_Alphabet = Alphabet.join(Alphabet[:-1])
Use itertools.cycle ans string.ascii_lowercase:
from itertools import cycle
import string
circular_alphabet = cycle(string.ascii_lowercase)
That is an infinite iterator with the lowercase letters:
>>> "".join(next(circular_alphabet ) for _ in range(50))
'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwx'
I think you have to use circular queue. for more information please check this link.
Alternative (old fashion?) solution:
def cycle_letter(ch,up=True):
upper = 'A' <= ch <= 'Z'
ch = ch.lower()
letters = 'abcdefghijklmnopqrstuvwxyz'
pos = letters.find(ch)
if pos < 0: return ch
length = len(letters)
pos += 1 if up else length-1
ans = letters[pos%length]
if upper: ans = ans.upper()
return ans
################################################################################
def cycle_string(s,up=True):
return ''.join(cycle_letter(ch,up) for ch in s)
################################################################################
if __name__ == '__main__': #Test
s = cycle_string('Hello, World!')
print(s)
s = cycle_string(s,False)
print(s)
In case it helps someone, this snippet shifts a word by the desired number of spaces. (e.g. shift_word('abcdef', 12) = 'opqrst' )
def shift_word(word: str, spaces: int) -> str:
first_ordinal = 97
last_ordinal = 122
alphabet_size = 26
return ''.join(chr((ord(letter) - last_ordinal - spaces - 1) % alphabet_size + first_ordinal) for letter in word)
It simply iterates over the word letter-by-letter, applies some modulo math to calculate the right "bucket" where the letter should fall, and makes sure the result is in the boundaries of ordinals 97-122 (letters a-z)
For instance, I have the following string:
Hello how are you today, [name]?
How would I go about randomly placing characters between a random choice of words but not [name]? I already I have this following piece of code but I was hoping there is a better way of going about it.
string = 'Hello how are you today, [name]?'
characters = 'qwertyuioplkjhgfdsazxcvbnm,. '
arr = string.rsplit(" ")
for i in range(0, len(arr)):
x = arr[i]
if x == '[name]':
continue
if (random.randint(0,2)==1) :
rnd=random.randint(1,len(x)-2)
tmp1 = random.randint(0,len(characters))
rndCharacter = characters[tmp1:tmp1+1]
x = x[0:rnd] + rndCharacter + x[rnd+1:]
arr[i] = x
" ".join(arr)
> Hellio how are yoy todsy, [name]?"
Though this replaces the character with a another random character. What way would I go about having it randomly replace or place a random character after or before a character as well?
Basically I'm just trying to simulate a sort of typo generator.
Thanks
Update on my code so far:
string = 'Hey how are you doing, [name]?'
characters = 'aeiou'
arr = string.rsplit(" ")
for i in range(0, len(arr)):
x = arr[i]
if x == '[name]': continue
if len(x) > 3:
if random.random() > 0.7:
rnd = random.randint(0,len(x)-1)
rndCharacter = random.choice(characters)
if random.random() > 0.7:
x = x[0:rnd] + rndCharacter + x[rnd+1:]
else:
x = x[:rnd] + rndCharacter + x[rnd:]
arr[i] = x
else:
if random.random() > 0.7:
rnd = random.randint(0,len(x)-1)
rndCharacter = random.choice(characters)
x = x[:rnd] + rndCharacter + x[rnd:]
arr[i] = x
print " ".join(arr)
> Hey houw are you doiang, [name]?
UPDATE:
Maybe my final update for the code, hopefully this will help someone out some point in the future
def misspeller(word):
typos = { 'a': 'aqwedcxzs',
'b': 'bgfv nh',
'c': 'cdx vf',
'd': 'desxcfr',
'e': 'e3wsdfr4',
'f': 'fredcvgt',
'g': 'gtrfvbhyt',
'h': 'hytgbnju',
'i': 'i8ujko9',
'j': 'juyhnmki',
'k': 'kiujm,lo',
'l': 'loik,.;p',
'm': 'mkjn ,',
'n': 'nhb mjh',
'o': 'o9ikl;p0',
'p': 'p0ol;[-',
'q': 'q1asw2',
'r': 'r4edft5',
's': 'swazxde',
't': 't5rfgy6',
'u': 'u7yhji8',
'v': 'vfc bg',
'w': 'w2qasde3',
'x': 'xszcd',
'y': 'y6tghu7',
'z': 'zaZxs',
' ': ' bvcnm',
'"': '"{:?}',
'\'': '[;/\']',
':': ':PL>?"{',
'<': '<LKM >',
'>': '>:L<?:',
';': ';pl,.;[',
'[': '[-p;\']=',
']': '=[\'',
'{': '{[_P:"}+',
'}': '}=[\']=',
'|': '|\]\'',
'.': '.l,/;',
',': ',lkm.'
}
index = random.randint(1,len(word)-1)
letter = list(word[:index])[-1].lower()
try:
if random.random() <= 0.5:
return word[:index] + random.choice(list(typos[letter])) + word[index:]
else:
return word[:index-1] + random.choice(list(typos[letter])) + word[index:]
except KeyError:
return word
def generate(self, s, n, safe_name):
misspelled_s = ''
misspelled_list = []
for item in s.split(' '):
if n:
if safe_name in item:
misspelled_list.append(item)
else:
r = random.randint(0,1)
if r == 1 and len(re.sub('[^A-Za-z0-9]+', '', item)) > 3:
misspelled_list.append(misspeller(item))
n -= 1
else:
misspelled_list.append(item)
else:
misspelled_list.append(item)
return ' '.join(misspelled_list)
import random
def misspeller(word):
characters = 'qwertyuioplkjhgfdsazxcvbnm,. '
rand_word_position = random.randint(-1,len(word))
rand_characters_position = random.randint(0,len(characters)-1)
if rand_word_position == -1:
misspelled_word = characters[rand_characters_position] + word
elif rand_word_position == len(word):
misspelled_word = word + characters[rand_characters_position]
else:
misspelled_word = list(word)
misspelled_word[rand_word_position] = characters[rand_characters_position]
misspelled_word = ''.join(misspelled_word)
return misspelled_word
s = 'Hello how are you today, [name]?'
misspelled_s = ''
misspelled_list = []
for item in s.split(' '):
if '[name]' in item:
misspelled_list.append(item)
else:
misspelled_list.append(misspeller(item))
misspelled_s = ' '.join(misspelled_list)
print misspelled_s
Examples of what I'm getting from misspelled_s are:
'Hellk howg ars youf poday, [name]?'
'Heylo how arer y,u todab, [name]?'
'Hrllo hfw are zyou totay, [name]?'
Edited to clean up a couple of mistakes and omissions on first copy.
Edit 2 If you don't want every word to be affected you can modify the for loop in the following way:
for item in s.split(' '):
n = random.randint(0,1)
if '[name]' in item:
misspelled_list.append(item)
elif n == 1:
misspelled_list.append(misspeller(item))
else:
misspelled_list.append(item)
You can modify the probability that a word is modified by changing how n is generated e.g. n = random.randint(0,10)
If you want to place a letter before or after instead of replacing, just fix the indices in your splicing so that they don't jump over a letter - i.e. use
x = x[:rnd] + rndCharacter + x[rnd:]
That way the new character will be inserted in the middle, instead of replacing an existing one.
Also, you can use rndCharacter = random.choice(characters) instead of using tmp1 like that.
I think #sgallen's answer will work, but I have a few tips (for your previous code, and going forward).
for i in range(0, len(arr)):
x = arr[i]
# is the same as
for i,x in enumerate(arr):
else:
if random...:
# to
elif random...:
Using string as the name of a variable, isn't a good practice. The reason being, there is a string module. It might even come in handy for this because of the string constants. Alternatives could be inp, or data, or sentence.
# For example
>>> import string
>>> string.lowercase
'abcdefghijklmnopqrstuvwxyz'
By the way, if anyone notices errors in the above, leave a comment. Thanks.
You can also use split('[name]'), and work on the sub-string, this way you'll be sure (see note below) of don't change '[name]'.
You may have problem splitting on every [name] occurance catching some substring of some longer name, but if you:
Use real and common names in capital letter (like Jonh).
Avoid the use of similar names.
Then the following code should work fine:
def typo(string):
index = random.randint(1,len(string)-1) # don't change first or last
return string[:index] + random.choice(characters) + string[index:]
def generate(string, n, safe_name):
sub_strings = string.split(safe_name)
while n:
sub_index = random.randint(0,len(sub_strings) - 1)
sub = sub_strings[sub_index]
if len(sub) <= 2: # if too short don't change
continue
sub_strings[sub_index] = typo(sub)
n -= 1
return safe_name.join(sub_strings)
Example adding 3 new random charachter:
>>> string = 'Hello how are you today, Alice?'
>>> generate(string, 3, 'Alice')
'Hellov howj are yoiu today, Alice?'
With the name occurring more then one time:
>>> string = 'Hello Alice, how are you today, Alice?'
>>> generate(string, 3, 'Alice')
'Hello Alice, hoiw arfe you todayq, Alice?'
For the example you have given, it looks like we can split it on the comma and put the typo(s) in the first part of the string.
If this is correct, you need to do three things randomly before generating the typo:
Choose which character to do the typo on or near
Choose the typo character
Choose one of three actions - Replace, Prefix, Append
Would this fit the bill?
(BTW, since you are familiar with random, I didn't give any code.)
You are "hoping there is a better way of going about it". Well, here's some suggestions, and some code demonstrating those suggestions. Some of the suggestions are about making the code more pythonic or easy to read, not just the mechanics of changing strings.
Use module re for regular expressions to detect "[name]". This will pay dividends as soon as you have more keywords than just this one.
for x in string.rsplit(" ") is a more pythonic way to loop through the words.
Get real-numbered randoms, and compare to a probability setting in range 0.0-1.0. More flexible than getting integers 0,1.
Use x[:rnd] + ... + x[rnd:x] as recommended by others, for easier string manipulation.
Use x if condition else y for a concise choice between alternatives, in this case between an index which causes overwriting and an index which causes insertion.
Your example output shows a typo inserted in "you", but your example code only inserts typos if len(x) > 3. I follow your code, but this is easy to change.
Hope this helps.
import random
import re
string = 'Hello how are you today, [name]?'
characters = 'qwertyuioplkjhgfdsazxcvbnm,. '
words = []
for x in string.rsplit(" "):
if None == re.search('[^\]]*\[[a-z]+\].*', x) \
and len(x) > 3 and random.random()<=0.5:
# rnd: index of char to overwrite or insert before
rnd = random.randint(2,len(x)-2)
# rnd1: index of 1st char after modification
# random.random <= 0.x is probability of overwriting instead of inserting
rnd1 = rnd + 1 if random.random() <= 0.5 else 0
x = x[:rnd] + random.choice(characters) + x[rnd1:]
words.append(x)
typos = " ".join(words)
print typos
Update: fixed indentation mistake in the code.
Update 2: made the code for choosing overwrite versus insert to be more concise.