tags:

views:

55

answers:

4

Suppose I have a regular expression (a)|(b)|(c)|(d). If I apply it to text 'foobar' I get a match object

>>> compiled = re.compile('(a)|(b)|(c)|(d)')
>>> compiled.search('foobar').groups()
(None, 'b', None, None)

How do I extract the 'b' from here? Or in general, how do I extract the first match from an unknown number of groups (can happen when the regexp was built dynamically)?

A: 
reduce(lambda x, y : (x, y)[x is None], groups, None)
Nikolai Ruhe
+4  A: 
>>> g = (None, 'b', None, None)
>>> next(x for x in g if x is not None)
'b'

>>> g = (None, None, None)
>>> next((x for x in g if x is not None), "default")  # try this with filter :)
'default'

>>> g = (None, None, None)  # so you know what happens, and what you could catch
>>> next(x for x in g if x is not None)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration
Roger Pate
Wow, that was difficult. Why Python doesn't have this as a builtin method for match group? Seems like a thing everyone invents over and over again hundreds and thousands of millions times. I am writing an angry letter to Python mailing list right now!
bodacydo
@bodacydo: I wouldn't mind if NoneType had a staticmethod named 'coalesce', but you can just as easily write the above single line into a function if this is difficult for you. As to why it doesn't.. *\*shrug\** doesn't matter to me, because it doesn't and I have no control over changing it. :)
Roger Pate
This is wrong thinking, everyone of us has control to change anything in open source projects!
bodacydo
@bodacydo: Okay, how about "It would take a lot of effort to get the maintainers of Python to do my bidding, this isn't an important issue for me, and I don't want to maintain it myself." :)
Roger Pate
+1  A: 
filter(lambda x : x is not None, groups)[0]
Nikolai Ruhe
+1  A: 
>>> g = (None,'b',None,None)
>>> filter(None,g)
('b',)
>>> h = (None,None,None)
>>> filter(None,h)
()
jleedev
Just remember it fails for empty strings, `g = (None, '')`.
Roger Pate