python replace multiple occurrences of string with different values - python

i am writing a script in python that replaces all the occurrences of an math functions such as log with there answers but soon after i came into this problem i am unable replace multiple occurrences of a function with its answer
text = "69+log(2)+log(3)-log(57)/420"
log_list = []
log_answer = []
z = ""
c = 0
hit_l = False
for r in text:
if hit_l:
c += 1
if c >= 4 and r != ")":
z += r
elif r == ")":
hit_l = False
if r == "l":
hit_l = True
log_list.append(z)
if z != '':
logs = log_list[-1]
logs = re.sub("og\\(", ";", logs)
log_list = logs.split(";")
for ans in log_list:
log_answer.append(math.log(int(ans)))
for a in log_answer:
text = re.sub(f"log\\({a}\\)", str(a), text)
i want to replace log(10) and log(2) with 1 and 0.301 respectively i tried using re.sub but it is not working i am not able to replace the respective functions with there answers any help will be appreciated thank you

Here is my take on this using eval along with re.sub with a callback function:
x = "log(10)+log(2)"
output = re.sub(r'log\((\d+(?:\.\d+)?)\)', lambda x: str(eval('math.log(' + x.group(1) + ', 10)')), x)
print(output) # 1.0+0.301029995664

As long as your string contains no spaces and there are + signs between different logarithmic functions, eval could be a way to do it.
>>> a = 'log(10)+log(2)'
>>> b = a.split('+')
>>> b
['log(10)', 'log(2)']
>>> from math import log10 as log
>>> [eval(i) for i in b]
[1.0, 0.3010299956639812]
EDIT:
You could repeatedly use str.replace method to replace all mathematical operators (if there are more than one) with whitespaces and eventually use str.split like:
>>> text.replace('+', ' ').replace('-', ' ').replace('*', ' ').replace('/', ' ').split()
['69', 'log(2)', 'log(3)', 'log(57)', '420']

Related

How to get portion of string from 2 different strings and concat?

I have 2 strings a and b with - as delimiter, want to get 3rd string by concatenating the substring upto last % from a (which is one-two-three-%whatever% in below example) and from string b, drop the substring upto number of dashes found in resultant string (which is 4 in below e.g., that gives bar-bazz), I did this so far, is there a better way?
>>> a='one-two-three-%whatever%-foo-bar'
>>> b='1one-2two-3three-4four-bar-bazz'
>>> k="%".join(a.split('%')[:-1]) + '%-'
>>> k
'one-two-three-%whatever%-'
>>> k.count('-')
4
>>> y=b.split("-",k.count('-'))[-1]
>>> y
'bar-bazz'
>>> k+y
'one-two-three-%whatever%-bar-bazz'
>>>
An alternative approach using Regex:
import re
a = 'one-two-three-%whatever%-foo-bar'
b = '1one-2two-3three-4four-bar-bazz'
part1 = re.findall(r".*%-",a)[0] # one-two-three-%whatever%-
num = part1.count("-") # 4
part2 = re.findall(r"\w+",b) # ['1one', '2two', '3three', '4four', 'bar', 'bazz']
part2 = '-'.join(part2[num:]) # bar-bazz
print(part1+part2) # one-two-three-%whatever%-bar-bazz
For the first substring obtained from a, you can use rsplit():
k = a.rsplit('%', 1)[0] + '%-'
The rest look good to me
Maybe a little shorter ?
a = 'one-two-three-%whatever%-foo-bar'
b = '1one-2two-3three-4four-bar-bazz'
def merge (a,b):
res = a[:a.rfind ('%')+1]+'-'
return (res + "-".join (b.split ("-")[res.count ('-'):]))
print (merge (a,b) == 'one-two-three-%whatever%-bar-bazz')
I personally get nervous when I need to manually increment indexes or concatenate bare strings.
This answer is pretty similar to hingev's, just without the additional concat/addition operators.
t = "-"
ix = list(reversed(a)).index("%")
t.join([s] + b.split(t)[len(a[:-ix].split(t)):])
yet another possible answer:
def custom_merge(a, b):
result = []
idx = 0
for x in itertools.zip_longest(a.split('-'), b.split('-')):
result.append(x[idx])
if x[0][0] == '%' == x[0][-1]:
idx = 1
return "-".join(result)
Your question is specific enough that you might be optimizing the wrong thing (a smaller piece of a bigger problem). That being said, one way that feels easier to follow, and avoids some of the repeated linear traversals (splits and joins and counts) would be this:
def funky_percent_join(a, b):
split_a = a.split('-')
split_b = b.split('-')
breakpoint = 0 # len(split_a) if all of a should be used on no %
for neg, segment in enumerate(reversed(split_a)):
if '%' in segment:
breakpoint = len(split_a) - neg
break
return '-'.join(split_a[:breakpoint] + split_b[breakpoint:])
and then
>>> funky_percent_join('one-two-three-%whatever%-foo-bar', '1one-2two-3three-4four-bar-bazz')
'one-two-three-%whatever%-bar-bazz'
print(f"one-two-three-%{''.join(a.split('%')[1])}%")
that would work for the first, and then you could do the same for the second, and when you're ready to concat, you can do:
part1 = str(f"one-two-three-%{''.join(a.split('%')[1])}%")
part2 = str(f"-{''.join(b.split('-')[-2])}-{''.join(b.split('-')[-1])}")
result = part1+part2
this way it'll grab whatever you set the a/b variables to, provided they follow the same format.
but then again, why not do something like:
result = str(a[:-8] + b[22:])

Find multiple elements in string in Python

my problem is that I need to find multiple elements in one string.
For example I got one string that looks like this:
line = if ((var.equals("INPUT")) || (var.equals("OUTPUT"))
and then i got this code to find everything between ' (" ' and ' ") '
char1 = '("'
char2 = '")'
add = line[line.find(char1)+2 : line.find(char2)]
list.append(add)
The current result is just:
['INPUT']
but I need the result to look like this:
['INPUT','OUTPUT', ...]
after it got the first match it stopped searching for other matches, but I need to find everything in that string that matches this search.
I also need to append every single match to the list.
The simplest:
>>> import re
>>> s = """line = if ((var.equals("INPUT")) || (var.equals("OUTPUT"))"""
>>> r = re.compile(r'\("(.*?)"\)')
>>> r.findall(s)
['INPUT', 'OUTPUT']
The trick is to use .*? which is a non-greedy *.
You should look into regular expressions because that's a perfect fit for what you're trying to achieve.
Let's examine a regular expression that does what you want:
import re
regex = re.compile(r'\("([^"]+)"\)')
It matches the string (" then captures anything that isn't a quotation mark and then matches ") at the end.
By using it with findall you will get all the captured groups:
In [1]: import re
In [2]: regex = re.compile(r'\("([^"]+)"\)')
In [3]: line = 'if ((var.equals("INPUT")) || (var.equals("OUTPUT"))'
In [4]: regex.findall(line)
Out[4]: ['INPUT', 'OUTPUT']
If you don't want to use regex, this will help you.
line = 'if ((var.equals("INPUT")) || (var.equals("OUTPUT"))'
char1 = '("'
char2 = '")'
add = line[line.find(char1)+2 : line.find(char2)]
list.append(add)
line1=line[line.find(char2)+1:]
add = line1[line1.find(char1)+2 : line1.find(char2)]
list.append(add)
print(list)
just add those 3 lines in your code, and you're done
if I understand you correct, than something like that is help you:
line = 'line = if ((var.equals("INPUT")) || (var.equals("OUTPUT"))'
items = []
start = 0
end = 0
c = 0;
while c < len(line):
if line[c] == '(' and line[c + 1] == '"':
start = c + 2
if line[c] == '"' and line[c + 1] == ')':
end = c
if start and end:
items.append(line[start:end])
start = end = None
c += 1
print(items) # ['INPUT', 'OUTPUT']

How to find and get rid of consecutive repeated punctuation signs without using regular expressions in python?

I want to get rid of repeated consecutive punctuation signs and only leave one of them.
If I have
string = 'Is it raining????',
I want to get
string = 'Is it raining?'
But I don't want to get rid of '...'
I also need to do this without using regular expressions. I am a beginner in python and would appreciate any advice or hint. Thanks :)
Yet another groupby approach:
from itertools import groupby
from string import punctuation
punc = set(punctuation) - set('.')
s = 'Thisss is ... a test!!! string,,,,, with 1234445556667 rrrrepeats????'
print(s)
newtext = []
for k, g in groupby(s):
if k in punc:
newtext.append(k)
else:
newtext.extend(g)
print(''.join(newtext))
output
Thisss is ... a test!!! string,,,,, with 1234445556667 rrrrepeats????
Thisss is ... a test! string, with 1234445556667 rrrrepeats?
import string
from itertools import groupby
# get all punctuation minus period.
puncs = set(string.punctuation)-set('.')
s = 'Is it raining???? No but...,,,, it is snowing!!!!!!!###!######'
# get count of consecutive characters
t = [[k,len(list(g))] for k, g in groupby(s)]
s = ''
for ele in t:
char = ele[0]
count = ele[1]
if char in puncs and count > 1:
count = 1
s+=char*count
print s
#Is it raining? No but..., it is snowing!#!###
How about the following kind of approach:
import string
text = 'Is it raining???? No,,,, but...,,,, it is snoooowing!!!!!!!'
for punctuation in string.punctuation:
if punctuation != '.':
while True:
replaced = text.replace(punctuation * 2, punctuation)
if replaced == text:
break
text = replaced
print(text)
This would give the following output:
Is it raining? No, but..., it is snoooowing!
Or for a more efficient version giving the same results:
import string
text = 'Is it raining???? No,,,, but...,,,, it is snoooowing!!!!!!!'
last = None
output = []
for c in text:
if c == '.':
output.append(c)
elif c != last:
if c in string.punctuation:
last = c
else:
last = None
output.append(c)
print(''.join(output))
from itertools import groupby
s = 'Is it raining???? okkkk!!! ll... yeh""" ok?'
replaceables = [ch for i, ch in enumerate(s) if i > 0 and s[i - 1] == ch and (not ch.isalpha() and ch != '.')]
replaceables = [list(g) for k, g in groupby(replaceables)]
start = 0
for replaceable in replaceables:
replaceable = ''.join(replaceable)
start = s.find(replaceable, start)
r = s[start:].replace(replaceable, '', 1)
s = s.replace(s[start:], r)
print s

Repair one string relative to another in Python

Query "AAAAA-AAACAAA-AAAAAA"
Reference "AA-AATAAAAAAATAAAAAA"
In Python,how do I repair a string (Query) relative to a Reference string where dashes in the query are substituted for the reference character, and dashes in the Reference string result in deletions in the corresponding Query character?
"AAAAA-AAACAAA-AAAAAA" should become
"AAAATAAACAAATAAAAAA"
(where parantheses here "AA()AA(T)AAACAAA(T)AAAAAA" highlight the modified characters)
Below is code that can repair the dashes in the Query relative to the reference which may or may not be helpful(line numbers are specific to the file, not relevant here, I apologize for the non-pythonic code!), but I cannot modify the Query according to dashes in the reference....
if "Query identifier" in line:
Query = line[24:-12]
if "-" in Query:
indices = [i for i, x in enumerate(Query) if x == "-"]
QueryStringUntilFirstDash = Query[:indices[0]]
found = 2
if found ==2 and "Reference identifier" in line:
Ref = line[24:-12]
if len(indices) == 1:
QueryDashToEnd.append(Query[indices[0]+1:])
print QueryStringUntilFirstDash+Ref[indices[0]]+str(QueryDashToEnd[0])
del(A[:])
else:
while y < len(indices):
y+=1
if y < len(indices):
DashesMiddleofQuery.append(Query[indices[y-1]:indices[y]])
DashesMiddleofQuerySubstitution = [B.replace('-', Ref[indices[y-1]]) for B in B]
Concat= ''.join(B)
del(B[:])
print UID
print Beg+str(Concat)+Query[indices[-1]+1:]+">1"
found = 0
y = 0
IIUC, something like this might work:
>>> query = "AAAAA-AAACAAA-AAAAAA"
>>> ref = "AA-AATAAAAAAATAAAAAA"
>>> fixed = ''.join(r if q == '-' else '' if r == '-' else q
... for q,r in zip(query, ref))
>>>
>>> fixed
'AAAATAAACAAATAAAAAA'
Or if you want to push the logic into a function:
>>> def fixer(q,r):
... if q == '-':
... return r
... if r == '-':
... return ''
... return q
...
>>> fixed = ''.join(map(fixer, query, ref))
>>> fixed
'AAAATAAACAAATAAAAAA'
I think it's easier to think in terms of pairs of characters, and what to do with those directly, rather than indices.

How can I increment a char?

I'm new to Python, coming from Java and C. How can I increment a char? In Java or C, chars and ints are practically interchangeable, and in certain loops, it's very useful to me to be able to do increment chars, and index arrays by chars.
How can I do this in Python? It's bad enough not having a traditional for(;;) looper - is there any way I can achieve what I want to achieve without having to rethink my entire strategy?
In Python 2.x, just use the ord and chr functions:
>>> ord('c')
99
>>> ord('c') + 1
100
>>> chr(ord('c') + 1)
'd'
>>>
Python 3.x makes this more organized and interesting, due to its clear distinction between bytes and unicode. By default, a "string" is unicode, so the above works (ord receives Unicode chars and chr produces them).
But if you're interested in bytes (such as for processing some binary data stream), things are even simpler:
>>> bstr = bytes('abc', 'utf-8')
>>> bstr
b'abc'
>>> bstr[0]
97
>>> bytes([97, 98, 99])
b'abc'
>>> bytes([bstr[0] + 1, 98, 99])
b'bbc'
"bad enough not having a traditional for(;;) looper"?? What?
Are you trying to do
import string
for c in string.lowercase:
...do something with c...
Or perhaps you're using string.uppercase or string.letters?
Python doesn't have for(;;) because there are often better ways to do it. It also doesn't have character math because it's not necessary, either.
Check this: USING FOR LOOP
for a in range(5):
x='A'
val=chr(ord(x) + a)
print(val)
LOOP OUTPUT: A B C D E
I came from PHP, where you can increment char (A to B, Z to AA, AA to AB etc.) using ++ operator. I made a simple function which does the same in Python. You can also change list of chars to whatever (lowercase, uppercase, etc.) is your need.
# Increment char (a -> b, az -> ba)
def inc_char(text, chlist = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'):
# Unique and sort
chlist = ''.join(sorted(set(str(chlist))))
chlen = len(chlist)
if not chlen:
return ''
text = str(text)
# Replace all chars but chlist
text = re.sub('[^' + chlist + ']', '', text)
if not len(text):
return chlist[0]
# Increment
inc = ''
over = False
for i in range(1, len(text)+1):
lchar = text[-i]
pos = chlist.find(lchar) + 1
if pos < chlen:
inc = chlist[pos] + inc
over = False
break
else:
inc = chlist[0] + inc
over = True
if over:
inc += chlist[0]
result = text[0:-len(inc)] + inc
return result
There is a way to increase character using ascii_letters from string package which ascii_letters is a string that contains all English alphabet, uppercase and lowercase:
>>> from string import ascii_letters
>>> ascii_letters[ascii_letters.index('a') + 1]
'b'
>>> ascii_letters
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
Also it can be done manually;
>>> letters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
>>> letters[letters.index('c') + 1]
'd'
def doubleChar(str):
result = ''
for char in str:
result += char * 2
return result
print(doubleChar("amar"))
output:
aammaarr
For me i made the fallowing as a test.
string_1="abcd"
def test(string_1):
i = 0
p = ""
x = len(string_1)
while i < x:
y = (string_1)[i]
i=i+1
s = chr(ord(y) + 1)
p=p+s
print(p)
test(string_1)

Categories