1

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)
5
  • 4
    What have you tried, and what exactly is the problem with it? Commented 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 appreciated Commented 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 code Commented 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. Commented 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. Commented Apr 18, 2021 at 20:19

3 Answers 3

2
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.

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you! This is better than what I came up with. The only thing I have modified is instead of the print statements, I've appended to a string so I can use it elsewhere
@CraigNathan, just edited my initial answer, the if condition now is shorter.
1

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

1

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.