This is my code :
def cap_space(txt):
e = txt
upper = "WLMFSC"
letters = [each for each in e if each in upper]
a = ''.join(letters)
b = a.lower()
c = txt.replace(a,' '+b)
return c
who i built to find the uppercase latters on a given string and replace it with space and the lowercase of the latter
example input :
print(cap_space('helloWorld!'))
print(cap_space('iLoveMyFriend'))
print(cap_space('iLikeSwimming'))
print(cap_space('takeCare'))
what should output be like :
hello world!
i love my friend
take care
i like swimming
what i get as output instead is :
hello world!
iLoveMyFriend
iLikeSwimming
take care
the problem here is the condition only applied if there only one upper case latter in the given string for some reasons how i could improve it to get it applied to every upper case latter on the given string ?
Being a regex addict, I can offer the following solution which relies on re.findall with an appropriate regex pattern:
def cap_space(txt):
parts = re.findall(r'^[a-z]+|[A-Z][a-z]*[^\w\s]?', txt)
output = ' '.join(parts).lower()
return output
inp = ['helloWorld!', 'iLoveMyFriend', 'iLikeSwimming', 'akeCare']
output = [cap_space(x) for x in inp]
print(inp)
print(output)
This prints:
['helloWorld!', 'iLoveMyFriend', 'iLikeSwimming', 'akeCare']
['hello world!', 'i love my friend', 'i like swimming', 'ake care']
Here is an explanation of the regex pattern used:
^[a-z]+ match an all lowercase word from the very start of the string
| OR
[A-Z] match a leading uppercase letter
[a-z]* followed by zero or more lowercase letters
[^\w\s]? followed by an optional "symbol" (defined here as any non word,
non whitespace character)
You can make use of nice python3 methods str.translate and str.maketrans:
In [281]: def cap_space(txt):
...: upper = "WLMFSC"
...: letters = [each for each in txt if each in upper]
...: d = {i: ' ' + i.lower() for i in letters}
...: return txt.translate(str.maketrans(d))
...:
...:
In [283]: print(cap_space('helloWorld!'))
...: print(cap_space('iLoveMyFriend'))
...: print(cap_space('iLikeSwimming'))
...: print(cap_space('takeCare'))
hello world!
i love my friend
i like swimming
take care
A simple and crude way. It might not be effective but it is easier to understand
def cap_space(sentence):
characters = []
for character in sentence:
if character.islower():
characters.append(character)
else:
characters.append(f' {character.lower()}')
return ''.join(characters)
a is all the matching uppercase letters combined into a single string. When you try to replace them with txt.replace(a, ' '+b), it will only match if all the matchinguppercase letters are consecutive in txt, or there's just a single match. str.replace() matches and replaces the whole seawrch string, not any characters in it.
Combining all the matches into a single string won't work. Just loop through txt, checking each character to see if it matches.
def cap_space(txt):
result = ''
upper = "WLMFSC"
for c in txt:
if c in upper:
result += ' ' + c.lower()
else:
result += c
return result
Related
This question already has answers here:
How to use re to find consecutive, repeated chars
(3 answers)
Closed 2 years ago.
I want to detect if there are three of the same letter next to each other in a string.
For example:
string1 = 'this is oooonly excaple' # ooo
string2 = 'nooo way that he did this' # ooo
string3 = 'I kneeeeeew it!' # eee
Is there any pythonic way to do this?
I guess that a solution like this is not the best one:
for letters in ['aaa', 'bbb', 'ccc', 'ddd', ..., 'zzz']:
if letters in string:
print(True)
you dont have to use regex but solution is little long for something as simple as that
def repeated(string, amount):
current = None
count = 0
for letter in string:
if letter == current:
count += 1
if count == amount:
return True
else:
count = 1
current = letter
return False
print(repeated("helllo", 3) == True)
print(repeated("hello", 3) == False)
You can use groupby to group similar letters and then check the length of each group:
from itertools import groupby
string = "this is ooonly an examplle nooo wway that he did this I kneeeeeew it!"
for letter, group in groupby(string):
if len(list(group)) >= 3:
print(letter)
Will output:
o
o
e
If you don't care for the letters themselves and just want to know if there was a repetition, take advantage of short-circuiting with the built-in any function:
print(any(len(list(group)) >= 3 for letter, group in groupby(string)))
One of the best ways to tackle these simple pattern problems is with regex
import re
test_cases = [
'abc',
'a bbb a', # expected match for 'bbb'
'bb a b',
'aaa c bbb', # expected match for 'aaa' and 'bbb'
]
for string in test_cases:
# We use re.findall because don't want to keep only with the first result.
# In case we want to stop at the first result, we should use re.search
match = re.findall(r'(?P<repeated_characters>(.)\2{2})', string)
if match:
print([groups[0] for groups in match])
Result:
['bbb']
['aaa', 'bbb']
Use a regular expression:
import re
pattern = r"(\w)\1{2}"
string = "this is ooonly an example"
print(re.search(pattern, string) is not None)
Output:
True
>>>
How about using regex? - ([a-z])\1{2}
>>> import re
>>> re.search(r'([a-z])\1{2}', 'I kneeew it!', flags=re.I)
<re.Match object; span=(4, 7), match='eee'>
re.search will return None if it doesn't find a match, otherwise it'll return a match object, you can get the full match from the match object using [0] on it.
string1 = 'nooo way that he did this'
for i in range(0,len(string1)-2):
sub_st = string1[i:i+3]
if sub_st[0]*3 == sub_st:
print('true')
print statement is from your example.
sub_st[0]*3 clone fist character in the sub_st combine those into single string. If original sub_st and clone one same it means sub_st carries the same latter 3 times.
If you don't need a general answer for n repetitions you can just iterate through the string and print true if previous character and next character are equal to current character, excluding the first and last character.
text = "I kneeeeeew it!"
for i in range(1,len(text)-1):
if text[i-1] == text[i] and text[i+1] == text[i]:
print(True)
break;
We can define following predicate with itertools.groupby + any functions like
from itertools import groupby
def has_repeated_letter(string):
return any(len(list(group)) >= 3 for _, group in groupby(string))
and after that use it
>>> has_repeated_letter('this is oooonly example')
True
>>> has_repeated_letter('nooo way that he did this')
True
>>> has_repeated_letter('I kneeeeeew it!')
True
>>> has_repeated_letter('I kneew it!')
False
we get a string from user and want to lowercase it and remove vowels and add a '.' before each letter of it. for example we get 'aBAcAba' and change it to '.b.c.b' . two early things are done but i want some help with third one.
str = input()
str=str.lower()
for i in range(0,len(str)):
str=str.replace('a','')
str=str.replace('e','')
str=str.replace('o','')
str=str.replace('i','')
str=str.replace('u','')
print(str)
for j in range(0,len(str)):
str=str.replace(str[j],('.'+str[j]))
print(str)
A few things:
You should avoid the variable name str because this is used by a builtin, so I've changed it to st
In the first part, no loop is necessary; replace will replace all occurrences of a substring
For the last part, it is probably easiest to loop through the string and build up a new string. Limiting this answer to basic syntax, a simple for loop will work.
st = input()
st=st.lower()
st=st.replace('a','')
st=st.replace('e','')
st=st.replace('o','')
st=st.replace('i','')
st=st.replace('u','')
print(st)
st_new = ''
for c in st:
st_new += '.' + c
print(st_new)
Another potential improvement: for the second part, you can also write a loop (instead of your five separate replace lines):
for c in 'aeiou':
st = st.replace(c, '')
Other possibilities using more advanced techniques:
For the second part, a regular expression could be used:
st = re.sub('[aeiou]', '', st)
For the third part, a generator expression could be used:
st_new = ''.join(f'.{c}' for c in st)
You can use str.join() to place some character in between all the existing characters, and then you can use string concatenation to place it again at the end:
# st = 'bcb'
st = '.' + '.'.join(st)
# '.b.c.b'
As a sidenote, please don't use str as a variable name. It's the name of the "string" datatype, and if you make a variable named it then you can't properly work with other strings any more. string, st, s, etc. are fine, as they're not the reserved keyword str.
z = "aBAcAba"
z = z.lower()
newstring = ''
for i in z:
if not i in 'aeiou':
newstring+='.'
newstring+=i
print(newstring)
Here I have gone step by step, first converting the string to lowercase, then checking if the word is not vowel, then add a dot to our final string then add the word to our final string.
You could try splitting the string into an array and then build a new string with the indexes of the array appending an "."
not too efficient but will work.
thanks to all of you especially allani. the bellow code worked.
st = input()
st=st.lower()
st=st.replace('a','')
st=st.replace('e','')
st=st.replace('o','')
st=st.replace('i','')
st=st.replace('u','')
print(st)
st_new = ''
for c in st:
st_new += '.' + c
print(st_new)
This does everything.
import re
data = 'KujhKyjiubBMNBHJGJhbvgqsauijuetystareFGcvb'
matches = re.compile('[^aeiou]', re.I).finditer(data)
final = f".{'.'.join([m.group().lower() for m in matches])}"
print(final)
#.k.j.h.k.y.j.b.b.m.n.b.h.j.g.j.h.b.v.g.q.s.j.t.y.s.t.r.f.g.c.v.b
s = input()
s = s.lower()
for i in s:
for x in ['a','e','i','o','u']:
if i == x:
s = s.replace(i,'')
new_s = ''
for i in s:
new_s += '.'+ i
print(new_s)
def add_dots(n):
return ".".join(n)
print(add_dots("test"))
def remove_dots(a):
return a.replace(".", "")
print(remove_dots("t.e.s.t"))
I am trying to reverse words of a string, but having difficulty, any assistance will be appreciated:
S = " what is my name"
def reversStr(S):
for x in range(len(S)):
return S[::-1]
break
What I get now is: eman ym si tahw
However, I am trying to get: tahw is ym eman (individual words reversed)
def reverseStr(s):
return ' '.join([x[::-1] for x in s.split(' ')])
orig = "what is my name"
reverse = ""
for word in orig.split():
reverse = "{} {}".format(reverse, word[::-1])
print(reverse)
Since everyone else's covered the case where the punctuation moves, I'll cover the one where you don't want the punctuation to move.
import re
def reverse_words(sentence):
return re.sub(r'[a-zA-Z]+', lambda x : x.group()[::-1], sentence)
Breaking this down.
re is python's regex module, and re.sub is the function in that module that handles substitutions. It has three required parameters.
The first is the regex you're matching by. In this case, I'm using r'\w+'. The r denotes a raw string, [a-zA-Z] matches all letters, and + means "at least one".
The second is either a string to substitute in, or a function that takes in a re.MatchObject and outputs a string. I'm using a lambda (or nameless) function that simply outputs the matched string, reversed.
The third is the string you want to do a find in a replace in.
So "What is my name?" -> "tahW si ym eman?"
Addendum:
I considered a regex of r'\w+' initially, because better unicode support (if the right flags are given), but \w also includes numbers and underscores. Matching - might also be desired behavior: the regexes would be r'[a-zA-Z-]+' (note trailing hyphen) and r'[\w-]+' but then you'd probably want to not match double-dashes (ie --) so more regex modifications might be needed.
The built-in reversed outputs a reversed object, which you have to cast back to string, so I generally prefer the [::-1] option.
inplace refers to modifying the object without creating a copy. Yes, like many of us has already pointed out that python strings are immutable. So technically we cannot reverse a python string datatype object inplace. However, if you use a mutable datatype, say bytearray for storing the string characters, you can actually reverse it inplace
#slicing creates copy; implies not-inplace reversing
def rev(x):
return x[-1::-1]
# inplace reversing, if input is bytearray datatype
def rev_inplace(x: bytearray):
i = 0; j = len(x)-1
while i<j:
t = x[i]
x[i] = x[j]
x[j] = t
i += 1; j -= 1
return x
Input:
x = bytearray(b'some string to reverse')
rev_inplace(x)
Output:
bytearray(b'esrever ot gnirts emose')
Try splitting each word in the string into a list (see: https://docs.python.org/2/library/stdtypes.html#str.split).
Example:
>>string = "This will be split up"
>>string_list = string.split(" ")
>>string_list
>>['This', 'will', 'be', 'split', 'up']
Then iterate through the list and reverse each constituent list item (i.e. word) which you have working already.
def reverse_in_place(phrase):
res = []
phrase = phrase.split(" ")
for word in phrase:
word = word[::-1]
res.append(word)
res = " ".join(res)
return res
[thread has been closed, but IMO, not well answered]
the python string.lib doesn't include an in place str.reverse() method.
So use the built in reversed() function call to accomplish the same thing.
>>> S = " what is my name"
>>> ("").join(reversed(S))
'eman ym si tahw'
There is no obvious way of reversing a string "truly" in-place with Python. However, you can do something like:
def reverse_string_inplace(string):
w = len(string)-1
p = w
while True:
q = string[p]
string = ' ' + string + q
w -= 1
if w < 0:
break
return string[(p+1)*2:]
Hope this makes sense.
In Python, strings are immutable. This means you cannot change the string once you have created it. So in-place reverse is not possible.
There are many ways to reverse the string in python, but memory allocation is required for that reversed string.
print(' '.join(word[::-1] for word in string))
s1 = input("Enter a string with multiple words:")
print(f'Original:{s1}')
print(f'Reverse is:{s1[::-1]}')
each_word_new_list = []
s1_split = s1.split()
for i in range(0,len(s1_split)):
each_word_new_list.append(s1_split[i][::-1])
print(f'New Reverse as List:{each_word_new_list}')
each_word_new_string=' '.join(each_word_new_list)
print(f'New Reverse as String:{each_word_new_string}')
If the sentence contains multiple spaces then usage of split() function will cause trouble because you won't know then how many spaces you need to rejoin after you reverse each word in the sentence. Below snippet might help:
# Sentence having multiple spaces
given_str = "I know this country runs by mafia "
tmp = ""
tmp_list = []
for i in given_str:
if i != ' ':
tmp = tmp + i
else:
if tmp == "":
tmp_list.append(i)
else:
tmp_list.append(tmp)
tmp_list.append(i)
tmp = ""
print(tmp_list)
rev_list = []
for x in tmp_list:
rev = x[::-1]
rev_list.append(rev)
print(rev_list)
print(''.join(rev_list))
output:
def rev(a):
if a == "":
return ""
else:
z = rev(a[1:]) + a[0]
return z
Reverse string --> gnirts esreveR
def rev(k):
y = rev(k).split()
for i in range(len(y)-1,-1,-1):
print y[i],
-->esreveR gnirts
How can I remove the all lowercase letters before and after "Johnson" in these strings?
str1 = 'aBcdJohnsonzZz'
str2 = 'asdVJohnsonkkk'
Expected results are as below:
str1 = 'BJohnsonZ'
str2 = 'VJohnson'
You can partition the string, check it had the separator, than translate out lowercase letters, eg:
from string import ascii_lowercase as alc
str1 = 'aBcdJohnsonzZz'
p1, sep, p2 = str1.partition('Johnson')
if sep:
str1 = p1.translate(None, alc) + sep + p2.translate(None, alc)
print str1
str.partition() is your friend here:
def munge(text, match):
prefix, match, suffix = text.partition(match)
prefix = "".join(c for c in prefix if not c.islower())
suffix = "".join(c for c in suffix if not c.islower())
return prefix + match + suffix
Example use:
>>> munge("aBcdJohnsonzZz", "Johnson")
'BJohnsonZ'
>>> munge("asdVJohnsonkkk", "Johnson")
'VJohnson'
import re
def foo(input_st, keep_st):
parts = input_st.split(keep_st)
clean_parts = [re.sub("[a-z]*", "", part) for part in parts]
return keep_st.join(clean_parts)
Other methods using the partition module don't seem to take into account your trigger word being repeated. This example will work in the case you have 'aBcJohnsonDeFJohnsonHiJkL' in the event that, that particular case is of concern to you.
There are a couple of ways you could tackle this. Here's the simplest one I could think of. The idea is to tackle it in three parts. First off, you need to know the middle string. In your case 'Johnson.' Then you can remove the lowercase letters from the part before and the part after.
def removeLowercaseAround(full, middle):
stop_at = full.index(middle) #the beginning of the name
start_again = stop_at+len(middle) #the end of the name
new_str = ''; #the string we'll return at the end
for i in range(stop_at): #for each char until the middle starts
if not full[i].islower(): #if it is not a lowercase char
new_str += full[i] #add it to the end of the new string
new_str+=middle #then add the middle char
for i in range(start_again, len(full)): #do the same thing with the end
if not full[i].islower(): #if it is not a lowercase char
new_str += full[i] #add it to the string
return new_str
print removeLowercaseAround('ABcdJohnsonzZZ', 'Johnson')
Not exactly very simple or streamlined, but you could do this sort of thing (based partially on Zero Piraeus')
(edited to reflect errors)
def remove_lower(string):
return ''.join(filter(str.isupper, string))
def strip_johnson(input_str):
prefix, match, postfix = input_str.partition("Johnson")
return (
remove_lower(prefix) +
match +
remove_lower(postfix)
)
I have the following piece of code. Basically, I'm trying to replace a word if it matches one of these regex patterns. If the word matches even once, the word should be completely gone from the new list. The code below works, however, I'm wondering if there's a way to implement this so that I can indefinitely add more patterns to the 'pat' list without having to write additional if statements within the for loop.
To clarify, my regex patterns have negative lookaheads and lookbehinds to make sure it's one word.
pat = [r'(?<![a-z][ ])Pacific(?![ ])', r'(?<![a-z][ ])Global(?![ ])']
if isinstance(x, list):
new = []
for i in x:
if re.search(pat[0], i):
i = re.sub(pat[0], '', i)
if re.search(pat[1], i):
i = re.sub(pat[1], '', i)
if len(i) > 0:
new.append(i)
x = new
else:
x = x.strip()
Just add another for loop:
for patn in pat:
if re.search(patn, i):
i = re.sub(patn, '', i)
if i:
new.append(i)
pat = [r'(?<![a-z][ ])Pacific(?![ ])', r'(?<![a-z][ ])Global(?![ ])']
if isinstance(x, list):
new = []
for i in x:
for p in pat:
i = re.sub(p, '', i)
if len(i) > 0:
new.append(i)
x = new
else:
x = x.strip()
Add another loop:
pat = [r'(?<![a-z][ ])Pacific(?![ ])', r'(?<![a-z][ ])Global(?![ ])']
if isinstance(x, list):
new = []
for i in x:
# iterate through pat list
for regx in pat:
if re.search(regx, i):
i = re.sub(regx, '', i)
...
If in your pattern, then changes are only the words, then you can add the words joined with | to make it or. So for your two patterns from the example will become one like below one.
r'(?<![a-z][ ])(?:Pacific|Global)(?![ ])'
If you need to add more words, just add with a pipe. For example (?:word1|word2|word3)
Inside the bracket ?: means do not capture the group.
something like this:
[word for word in l if not any(re.search(p, word) for p in pat)]
I will attempt a guess here; if I am wrong, please skip to the "this is how I'd write it" and modify the code that I provide, according to what you intend to do (which I may have failed to understand).
I am assuming you are trying to eliminate the words "Global" and "Pacific" in a list of phrases that may contain them.
If that is the case, I think your regular expression does not do what you specify. You probably intended to have something like the following (which does not work as-is!):
pat = [r'(?<=[a-z][ ])Pacific(?=[ ])', r'(?<=[a-z][ ])Global(?=[ ])']
The difference is in the look-ahead patterns, which are positive ((?=...) and (?<=...)) instead of negative ((?!...) and (?<!...)).
Furthermore, writing your regular expressions like this will not always correctly eliminate white space between your words.
This is how I'd write it:
words = ['Pacific', 'Global']
pat = "|".join(r'\b' + word + r'\b\s*' for word in words)
if isinstance(x, str):
x = x.strip() # I don't understand why you don't sub here, anyway!
else:
x = [s for s in (re.sub(pat, '', s) for s in x) if s != '']
In the regular expression for patterns, notice (a) \b, standing for "the empty string, but only at the beginning or end of a word" (see the manual), (b) the use of | for separating alternative patterns, and (c) \s, standing for "characters considered whitespace". The latter is what takes care of correctly removing unnecessary space after each eliminated word.
This works correctly in both Python 2 and Python 3. I think the code is much clearer and, in terms of efficiency, it's best if you leave re to do its work instead of testing each pattern separately.
Given:
x = ["from Global a to Pacific b",
"Global Pacific",
"Pacific Global",
"none",
"only Global and that's it"]
this produces:
x = ['from a to b', 'none', "only and that's it"]