TAGS :Viewed: 18 - Published at: a few seconds ago

[ Python: Using find function not in order ]

So the code below takes a string of inputted information (A math expression), and uses the find function to find one of the operators in "*/+-" and separates the string accordingly.

def splitting1(z):
    for operators in "*/+-":
        if operators in z:
            position1= z.find(operators)
            position2= z.rfind(operators)
            text_before_operators= (z[:position1]).strip()
            text_after_operators= (z[(position1+1):(position2)]).strip()
            return text_before_operators,text_after_operators

My problem is that if I have an inputted expression such as 3/5*7 then position1 will first find * before finding /. I want the code to associate 'position1' with the left most operator. Is there a way to omit operator precedence when using the for/in functions? If not, is there a better string manipulator that can omit the order of precedence.

Note z is the input. And the input is limited to two operators in case that created ambiguity.

Answer 1


You're iterating over */+-, so the first character that's found is the first one that's returned.

You basically want to find the indexes of all of these operators and then find the largest or the smallest. Try re-writing this function to work for other side of the string:

def find_operator_right(text):
    position = -1

    for oper in '*/+-':
        index = text.rfind(oper)

        if index > position:
            position = index

    return position

A slightly more Pythonic solution would be something like this:

right_index = max(map(text.rfind, '+-/*'))

Answer 2


It looks like you are trying to lex, so I suggest you look into modules designed especially for this purpose, for example ply.

.

Saying that, I think you are on the right track for this example, but you are missing some recursion (to make a more general lexer for these):

def splitting1(z):
    for char in "*/+-":
        if char in z:
            position = z.find(char)
            text_before_operator= (z[:position]).strip()
            text_after_operator= (z[position+1:]).strip()
            return (char, splitting1(text_before_operator), splitting1(text_after_operator))
    return ("number", z)

One way to find the left-most operator regardless of precedence i.e. omit operator precedence, is to rearrange what you iterate over:

def splitting2(z):
    for char in z:
        if char in "*/+-":
            position = z.find(char)
            text_before_operator= (z[:position]).strip()
            text_after_operator= (z[position+1:]).strip()
            return (char, splitting2(text_before_operator), splitting2(text_after_operator))
    return ("number", z)

Note these function return a different result to your original function.