Add text between strings as needed - python

I want something that replaces text between two occurences of the same string as follows:
Input:- "abcdefghcd","cd","k"
Output :- "abkefghk"
You might think that a simple thing such a .replace() would work, but actually its not that. Some more examples-
Input:- "123*45","*","u"
Output:- "123*45" # No change because there aren't two occurences of "*"
Input:- "text*text*hello*text","*","k"
Output:- "textktextkhello*text"
I don't know how to do it. Any ideas?

Count the occurrences and only replace the first n-1 of them if n is odd.
>>> s, find, replace = "text*text*hello*text", "*", "k"
>>> s.replace(find, replace, 2*(s.count(find)//2))
'textktextkhello*text'

what about splitting and joining :
Input = "abcdefghcd"
replace_="cd"
with_='k'
data=Input.split(replace_)
print(with_.join(data))
output:
abkefghk

Split the string and only substitute pattern if more than 2 occurrences are found.
>>> replace = lambda s, pat, sub: "".join([x + sub for x in s.split(pat) if x]) if len(s.split(pat))>2 else s
>>> replace("abcdefghcd", "cd", "k")
'abkefghk'
>>> replace("123*45", "*", "u")
'123*45'
If you favor an explicit function (recommended) instead of a one-liner:
def replace(s, pat, sub, occ=2):
"""Return a string of replaced letters unless below the occurrences."""
if len(s.split(pat)) > occ:
return "".join([x + sub for x in s.split(pat) if x])
return s

Related

How can I convert a string to dictionary in a manner where I have to extract key and value from same string

I need to convert string to dictionary in a manner for example
str1 = "00001000-0009efff : a 00100000-656b2fff : b"
Output what I require is
dict1 = {'a':['00001000','0009efff'], 'b':['00100000','656b2fff']}
Note: str1 can have many more such c, d, e with range.
You can do it with a regex:
import re
pattern = r'([\w\-]+) : ([\w\.]+)'
out = {m[1]: m[0].split('-') for m in re.findall(pattern, str1)}
Explanation of the regex:
match combination of alphanumeric characters and dashes [\w-]+
followed by a space, a colon and a space _:_
followed by a combination of alphanumeric characters and dot [\w\.]+
The groups are catching your relevant infos.
Assuming you only have a single key letter for each value
str1 = str1.replace(" : ", ":").split(" ")
output = {}
for _, s in enumerate(str1):
output[s[-1]] = s[:-2].split("-")
This code will work in general
str1 = "00001000-0009efff : a 00100000-656b2fff : b"
needed_dictionary = dict()
split_string = str1.split()
for i in range(len(split_string)):
if split_string[i] == ":":
needed_dictionary[split_string[i+1]]= split_string[i-1].split("-")
print(needed_dictionary)
But in Case the values or keys have "-" or ":" in them then this will fail.

Extract letters (and a specific number) from a string

I have a list of strings similar to the one below:
l = ['ad2g3f234','4jafg32','fg23g523']
For each string in l, I want to delete every digit (except for 2 and 3 if they appear as 23). So in this case, I want the following outcome:
n = ['adgf23','jafg','fg23g23']
How do I go about this? I tried re.findall like:
w = [re.findall(r'[a-zA-Z]+',t) for t in l]
but it doesn't give my desired outcome.
You can capture 23 in a group, and remove all other digits. In the replacement, use the group which holds 23 if it is there, else replace with an empty string.
import re
l = ['ad2g3f234', '4jafg32', 'fg23g523']
result = [
re.sub(
r"(23)|(?:(?!23)\d)+",
lambda m: m.group(1) if m.group(1) else "", s) for s in l
]
print(result)
Output
['adgf23', 'jafg', 'fg23g23']
Python demo
One way would be just to replace the string twice:
[re.sub("\d", "", i.replace("23", "*")).replace("*", "23") for i in l]
Output:
['adgf23', 'jafg', 'fg23g23']
Use a placeholder with re.sub
l = ['ad2g3f234','4jafg32','fg23g523']
w = [re.sub('#','23',re.sub('\d','',re.sub('23','#',t))) for t in l]
['adgf23', 'jafg', 'fg23g23']
EDIT
As answered by Chris, the approach is the same although string replace will be a better alternative stack_comparison
Using re.sub with function
import re
def replace(m):
if m.group() == '23':
return m.group()
else:
return ''
l = ['ad2g3f234','4jafg32','fg23g523']
w = [re.sub(r'23|\d', replace, x) for x in l]
#w: ['adgf23', 'jafg', 'fg23g23']
Explanation
re.sub(r'23|\d', replace, x)
- checks first for 23, next for a digit
- replace function leaves alone match with 23
- changes match with digit to null string.

how to add a dot before each letter in a string in python

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"))

How do I reverse words in a string with Python

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

python lambda, filtering out non alpha characters

i'm trying to keep only the letters in a string. i am trying to do something like this:
s = '1208uds9f8sdf978qh39h9i#H(&#*H(&H97dgh'
s_ = lambda: letter if letter.isalpha(), s
this errors out. how would a working version look?
Alternately:
s_ = filter(lambda c: c.isalpha(), s)
how about
re.sub('[^a-zA-Z]','', s)
or
"".join([x for x in s if x.isalpha()])
One handy way to manipulate strings is using a generator function and the join method:
result = "".join( letter for letter in s if letter.isalpha() )
You don't need a lambda function:
result = ''.join(c for c in input_str if c.isalpha())
If you really want to use a lambda function you could write it as follows:
result = ''.join(filter(lambda c:str.isalpha(c), input_str))
But this can also be simplified to:
result = ''.join(filter(str.isalpha, input_str))
You probably want a list comprehension here:
s_ = [letter for letter in s if letter.isalpha()]
However, this will give you a list of strings (each one character long). To convert this into a single string, you can use join:
s2 = ''.join(s_)
If you want, you can combine the two into a single statement:
s_ = ''.join(letter for letter in s if letter.isalpha())
If you particularly want or need to use a lambda function, you can use filter instead of the generator:
my_func = lambda letter: letter.isalpha()
s_ = ''.join(filter(my_func, s))
>>> s = '1208uds9f8sdf978qh39h9i#H(&#*H(&H97dgh'
>>> ''.join(e for e in s if e.isalpha())
'udsfsdfqhhiHHHdgh'
This is kind of the long way round, but will let you create a filter for any arbitrary set of characters.
import string
def strfilter(validChars):
vc = set(validChars)
def filter(s):
return ''.join(ch for ch in s if ch in vc)
return filter
filterAlpha = strfilter(string.letters)
filterAlpha('1208uds9f8sdf978qh39h9i#H(&#*H(&H97dgh') # -> 'udsfsdfqhhiHHHdgh'

Categories