Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Alternative to the `match = re.match(); if match: ...` idiom?

Tags:

python

idioms

If you want to check if something matches a regex, if so, print the first group, you do..

import re match = re.match("(\d+)g", "123g") if match is not None:     print match.group(1) 

This is completely pedantic, but the intermediate match variable is a bit annoying..

Languages like Perl do this by creating new $1..$9 variables for match groups, like..

if($blah ~= /(\d+)g/){     print $1 } 

From this reddit comment,

with re_context.match('^blah', s) as match:     if match:         ...     else:         ... 

..which I thought was an interesting idea, so I wrote a simple implementation of it:

#!/usr/bin/env python2.6 import re  class SRE_Match_Wrapper:     def __init__(self, match):         self.match = match      def __exit__(self, type, value, tb):         pass      def __enter__(self):         return self.match      def __getattr__(self, name):         if name == "__exit__":             return self.__exit__         elif name == "__enter__":             return self.__name__         else:             return getattr(self.match, name)  def rematch(pattern, inp):     matcher = re.compile(pattern)     x = SRE_Match_Wrapper(matcher.match(inp))     return x     return match  if __name__ == '__main__':     # Example:     with rematch("(\d+)g", "123g") as m:         if m:             print(m.group(1))      with rematch("(\d+)g", "123") as m:         if m:             print(m.group(1)) 

(This functionality could theoretically be patched into the _sre.SRE_Match object)

It would be nice if you could skip the execution of the with statement's code block, if there was no match, which would simplify this to..

with rematch("(\d+)g", "123") as m:     print(m.group(1)) # only executed if the match occurred 

..but this seems impossible based of what I can deduce from PEP 343

Any ideas? As I said, this is really trivial annoyance, almost to the point of being code-golf..

like image 563
dbr Avatar asked Jul 20 '09 08:07

dbr


People also ask

What is the difference between the re match () and the Search () methods?

There is a difference between the use of both functions. Both return the first match of a substring found in the string, but re. match() searches only from the beginning of the string and return match object if found.

What does match () do in Python?

match() function of re in Python will search the regular expression pattern and return the first occurrence. The Python RegEx Match method checks for a match only at the beginning of the string. So, if a match is found in the first line, it returns the match object.

What is re match object in Python?

Python re. match() method looks for the regex pattern only at the beginning of the target string and returns match object if match found; otherwise, it will return None.

How do you're match in Python?

Python has a module named re to work with RegEx. Here's an example: import re pattern = '^a...s$' test_string = 'abyss' result = re. match(pattern, test_string) if result: print("Search successful.") else: print("Search unsuccessful.")


2 Answers

I don't think it's trivial. I don't want to have to sprinkle a redundant conditional around my code if I'm writing code like that often.

This is slightly odd, but you can do this with an iterator:

import re  def rematch(pattern, inp):     matcher = re.compile(pattern)     matches = matcher.match(inp)     if matches:         yield matches  if __name__ == '__main__':     for m in rematch("(\d+)g", "123g"):         print(m.group(1)) 

The odd thing is that it's using an iterator for something that isn't iterating--it's closer to a conditional, and at first glance it might look like it's going to yield multiple results for each match.

It does seem odd that a context manager can't cause its managed function to be skipped entirely; while that's not explicitly one of the use cases of "with", it seems like a natural extension.

like image 117
Glenn Maynard Avatar answered Sep 20 '22 12:09

Glenn Maynard


Starting Python 3.8, and the introduction of assignment expressions (PEP 572) (:= operator), we can now capture the condition value re.match(r'(\d+)g', '123g') in a variable match in order to both check if it's not None and then re-use it within the body of the condition:

>>> if match := re.match(r'(\d+)g', '123g'): ...   print(match.group(1)) ...  123 >>> if match := re.match(r'(\d+)g', 'dddf'): ...   print(match.group(1)) ... >>> 
like image 23
Xavier Guihot Avatar answered Sep 20 '22 12:09

Xavier Guihot