I switched from Perl to Python about a year ago and haven\'t looked back. There is only one idiom that I\'ve ever found I can do more easily in Perl than in Python:<
I'd suggest this, as it uses the least regex to accomplish your goal. It is still functional code, but no worse then your old Perl.
import re
var = "barbazfoo"
m = re.search(r'(foo|bar|baz)(.+)', var)
if m.group(1) == 'foo':
print m.group(1)
# do something with m.group(1)
elif m.group(1) == "bar":
print m.group(1)
# do something with m.group(1)
elif m.group(1) == "baz":
print m.group(2)
# do something with m.group(2)
Starting Python 3.8
, and the introduction of assignment expressions (PEP 572) (:=
operator), we can now capture the condition value re.search(pattern, text)
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.search(r'foo(.+)', text):
# do something with match.group(1)
elif match := re.search(r'bar(.+)', text):
# do something with match.group(1)
elif match := re.search(r'baz(.+)', text)
# do something with match.group(1)
import re
s = '1.23 Million equals to 1230000'
s = re.sub("([\d.]+)(\s*)Million", lambda m: str(round(float(m.groups()[0]) * 1000_000))+m.groups()[1], s)
print(s)
1230000 equals to 1230000
Using named groups and a dispatch table:
r = re.compile(r'(?P<cmd>foo|bar|baz)(?P<data>.+)')
def do_foo(data):
...
def do_bar(data):
...
def do_baz(data):
...
dispatch = {
'foo': do_foo,
'bar': do_bar,
'baz': do_baz,
}
m = r.match(var)
if m:
dispatch[m.group('cmd')](m.group('data'))
With a little bit of introspection you can auto-generate the regexp and the dispatch table.
Here's the way I solved this issue:
matched = False;
m = re.match("regex1");
if not matched and m:
#do something
matched = True;
m = re.match("regex2");
if not matched and m:
#do something else
matched = True;
m = re.match("regex3");
if not matched and m:
#do yet something else
matched = True;
Not nearly as clean as the original pattern. However, it is simple, straightforward and doesn't require extra modules or that you change the original regexs.
Expanding on the solution by Pat Notz a bit, I found it even the more elegant to:
- name the methods the same as re
provides (e.g. search()
vs. check()
) and
- implement the necessary methods like group()
on the holder object itself:
class Re(object):
def __init__(self):
self.result = None
def search(self, pattern, text):
self.result = re.search(pattern, text)
return self.result
def group(self, index):
return self.result.group(index)
Instead of e.g. this:
m = re.search(r'set ([^ ]+) to ([^ ]+)', line)
if m:
vars[m.group(1)] = m.group(2)
else:
m = re.search(r'print ([^ ]+)', line)
if m:
print(vars[m.group(1)])
else:
m = re.search(r'add ([^ ]+) to ([^ ]+)', line)
if m:
vars[m.group(2)] += vars[m.group(1)]
One does just this:
m = Re()
...
if m.search(r'set ([^ ]+) to ([^ ]+)', line):
vars[m.group(1)] = m.group(2)
elif m.search(r'print ([^ ]+)', line):
print(vars[m.group(1)])
elif m.search(r'add ([^ ]+) to ([^ ]+)', line):
vars[m.group(2)] += vars[m.group(1)]
Looks very natural in the end, does not need too many code changes when moving from Perl and avoids the problems with global state like some other solutions.