Given a string with variables and parentheses:
'a((bc)((de)f))'
and a string of operators:
'+-+-+'
I would like to insert each operator (in order) into the first string between the following patterns (where char is defined as a character that is not an open or close parenthesis):
- char followed by char
- char followed by '('
- ')' followed by '('
- ')' followed by char
To give the result:
'a+((b-c)+((d-e)+f))'
Edit: I got it to work with the following code, but is there a more elegant way to do this, i.e. without a for loop?
x = 'a((bc)((de)f))'
operators = '+-+-+'
y = x
z = 0
for i in range(len(x)):
if i < len(x)-1:
xx = x[i]
isChar = True if x[i] != '(' and x[i] != ')' else False
isPO = True if x[i] == '(' else False
isPC = True if x[i] == ')' else False
isNxtChar = True if x[i+1] != '(' and x[i+1] != ')' else False
isNxtPO = True if x[i+1] == '(' else False
isNxtPC = True if x[i+1] == ')' else False
if (isChar and (isNxtChar or isNxtPO)) or (isPC and (isNxtPO or isNxtChar)):
aa = operators[z]
split1 = x[:i+1]
split2 = x[i+1:]
y = y[:i+z+1] + operators[z] + x[i+1:]
if z+1 < len(operators):
z+=1
print (y)
-
4What have you tried, and what exactly is the problem with it?jonrsharpe– jonrsharpe2021年04月18日 19:44:41 +00:00Commented Apr 18, 2021 at 19:44
-
@jonrsharpe I edited my post with functioning code, but if you have any suggestions how to make it better anything is appreciatedCraig Nathan– Craig Nathan2021年04月18日 20:10:03 +00:00Commented Apr 18, 2021 at 20:10
-
@JohnColeman sorry, I didn't mean it like that. I'm just looking for the most efficient way to do this with the least amount of codeCraig Nathan– Craig Nathan2021年04月18日 20:10:39 +00:00Commented Apr 18, 2021 at 20:10
-
1"better" how, exactly? Elegance isn't an objective measure. If you have working code that you think could be improved, see Code Review.jonrsharpe– jonrsharpe2021年04月18日 20:12:07 +00:00Commented Apr 18, 2021 at 20:12
-
My code wasn't working at the time of my post. I got it working after asking. Do you or anyone have any suggestions on how to achieve the result without using a for loop? I wasn't aware of code review, thank you for pointing that out. I can post there as well.Craig Nathan– Craig Nathan2021年04月18日 20:19:34 +00:00Commented Apr 18, 2021 at 20:19
3 Answers 3
initialExpr = 'a((bc)((de)f))'
operators = '+-+-+'
countOp = 0
countChar = 0
for char in initialExpr:
countChar += 1
print(char,end='')
if countChar < len(initialExpr) and (char == ')' or char.isalpha()) and (initialExpr[countChar] == '(' or initialExpr[countChar].isalpha()):
print(operators[countOp], end='')
countOp += 1
This should do the job. Assumption is the the variables, parenthesis and operators are in the right order and number.
2 Comments
One-liner using re:
import re
s = "a((bc)((de)f))"
o = "+-+-+"
print(
re.sub(
r"(?:[a-z](?:\(|[a-z]))|(?:\)(?:\(|[a-z]))",
lambda g, i=iter(o): next(i).join(g.group()),
s,
)
)
Prints:
a+((b-c)+((d-e)+f))
Comments
You can use a regex matching the pairs of characters inside which you want to insert an operator.
Then, you can use re.sub with a replacement function that joins the two characters with the next operator.
We can use a class with a __call__ method, that uses an iterator on the operators:
import re
rules = re.compile(r'[a-z]{2}|[a-z]\(|\)\(|\)[a-z]')
class Replace:
def __init__(self, operators):
self.it_operators = iter(operators)
def __call__(self, match):
return next(self.it_operators).join(match.group())
variables = 'a((bc)((de)f))'
operators = '+-+-+'
print(rules.sub(Replace(operators), variables))
# a+((b-c)+((d-e)+f))
Replace(operators) returns a callable Replace instance with an it_operators attribute that is an iterator, ready to iterate on the operators.
For each matching pair of characters, sub calls this instance, and its __call__ method returns the replacement for the two characters, that it builds by joining them with the next operator.