0

I need to do re.match sequentially, and in match case I need result of match to optain groups. Now I can do next:

r = re.match('cond1', l)
if r:
    # work with r.group()
else:
    r = re.match('cond2', l)
    if r:
        # work with r.group()
    else:
        r = re.match('cond3', l)
        if r:
            # work with r.group()

etc. But how can I do better? I see it is not possible to perform assignment in if like this:

if r = re.match('cond1', l):
    # work with r.group()
elif r = re.match('cond2', l):
    # work with r.group()
elif r = re.match('cond3', l)
    # work with r.group()
5
  • No it is not possible. Commented Nov 7, 2014 at 22:18
  • Yes, I realized it, but how to deal with such problem better? Commented Nov 7, 2014 at 22:20
  • Normally, when you're trying to chain 3 or more things together, it's better to ask how to chain any arbitrary number of things together. Which usually means a loop (or an implicit loop, e.g., in a call to map, or a recursive function). Commented Nov 7, 2014 at 22:21
  • Also, if you're literally matching these three patterns, why not just r = re.match('cond[123]', l)? Commented Nov 7, 2014 at 22:23
  • Your cascading ifs are fine (functional, intelligable, normal, and easy to understand in six months when you come back to this code to fix a bug.. ;-) Commented Nov 7, 2014 at 22:27

2 Answers 2

3

You could use a comprehension:

r, cond = next((m,c) for (m,c) in ((re.match(cond, line), cond) for cond in ('cond1', 'cond2', 'cond3')) if m)

if cond=='cond1':
    # work with r.group() for cond1
elif cond=='cond2':
    # work with r.group() for cond2

Or if that looks too arcane, a loop:

for cond in ('cond1', 'cond2', 'cond3'):
    r = re.match(cond, line)
    if r:
        break

if not r:
    # no match
elif cond=='cond1':
    # work with r.group() for cond1
elif cond=='cond2':
    # work with r.group() for cond2
Sign up to request clarification or add additional context in comments.

Comments

1

First, it often helps to refactor things out into functions. In this case, it helps because you can easily return early from a function; you can't return early from a block of code in the middle of other code.

def first_match(haystack):
    r = re.match('cond1', haystack)
    if r:
        # work with r.group()
        return
    r = re.match('cond2', l)
    if r:
        # work with r.group()
        return
    r = re.match('cond3', l)
    if r:
        # work with r.group()

All the else bits and indentation headaches go away.


Also, in general, when you're asking how to chain 3 or more things together, the right answer is to figure out how to chain any arbitrary number of things together, and just do that with N=3. Which usually means a loop (or a loop hidden inside a function like map, or a recursive function definition, etc.). For example:

def first_match(exprs, haystack):
    for expr in exprs:
        r = re.match(expr, haystack)
        if r:
            return r

In this case, however, what you're trying to do is actually doable. Maybe not a good idea, but… A regex match object is always truthy. And of course None is falsey. So:

r = re.match('cond1', l) or re.match('cond2', l) or re.match('cond3', l)
if r:
    # work with r.group(), which is the group for whichever matched

But notice that if you want to use the truthiness, you can do that in a loop too:

next(filter(bool, (re.match(cond, l) for cond in ('cond1', 'cond2', 'cond3'))))

Finally, you're already using regular expressions, so why not use regular expressions?

r = re.match('cond[123]', l)
if r:
    # work with r.group()

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.