Difference between revisions of "RegEx Python"

From Noah.org
Jump to navigationJump to search
Line 58: Line 58:
 
</pre>
 
</pre>
  
== Some Common RegEx Patterns ==
+
== Common Short RegEx Patterns ==
  
These are some patterns that I often find use for.
+
These are some regex patterns that I have found come up often. These examples assume a string, called page, that could, for instance, be an HTML document downloaded from the web. They will return a list of all non-overlapping matches found on the page.
These are not always perfect, but usually get the job done.
 
For example, it's almost impossible to match a legal email address
 
with a small, concise  regex, but this one will match most.
 
  
 
<pre>
 
<pre>
urls = re.findall("http://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+", page)
+
fin = urllib.urlopen('http://www.example.com/index.html')
emails = re.findall("[a-zA-Z0-9+_\-\.]+@[0-9a-zA-Z][.-0-9a-zA-Z]*.[a-zA-Z]+", page)
+
lines = fin.readlines()
ips = re.findall("(?:[\d]{1,3})\.(?:[\d]{1,3})\.(?:[\d]{1,3})\.(?:[\d]{1,3})", page)
+
fin.close()
 +
page = str(lines)
 +
</pre>
 +
 
 +
=== email regex pattern ===
 +
 
 +
It's almost impossible to match a legal email address with a small, concise regex, but this one will match most.
 +
 
 +
<pre>
 +
emails = re.findall('[a-zA-Z0-9+_\-\.]+@[0-9a-zA-Z][.-0-9a-zA-Z]*.[a-zA-Z]+', page)
 +
</pre>
 +
 
 +
=== URL regex pattern ===
 +
 
 +
<pre>
 +
urls = re.findall('http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+', page)
 +
</pre>
 +
 
 +
=== IP address regex pattern ===
 +
 
 +
<pre>
 +
ips = re.findall('(?:[\d]{1,3})\.(?:[\d]{1,3})\.(?:[\d]{1,3})\.(?:[\d]{1,3})', page)
 
</pre>
 
</pre>

Revision as of 13:21, 2 September 2008


These notes cover Regular Expressions in Python syntax. The information might be useful for other RE engines, but these are focused on Python's RE syntax.

Pulling a block of text out of another

The following will find any multiline block of HTML comments that begin with "<!-- EDIT". This can be addaped for anytime you want to pull one chunk of string out of another. Note, don't confuse the fact that we are looking for a multiline block with needing the re.MULTILINE flag. In fact we need the re.DOTALL flag, which we pass using the pattern syntax for flags.

 print re.findall("(?s)<!-- EDIT.*?-->", string)[0]

Compilation Flags -- inline

Python regex flags effect matching. For example: re.MULTILINE, re.IGNORECASE, re.DOTALL. Unfortunately, passing these flags is awkward if want to put regex patterns in a config file or database or otherwise want to have the user be able to enter in regex patterns. You don't want to have to make the user pass in flags separately. Luckily, you can pass flags in the pattern itself. This is a very poorly documented feature of Python regular expressions. At the start of the pattern add flags like this:

 (?i) for re.IGNORECASE
 (?L) for re.LOCALE (Make \w, \W, \b, \B, \s and \S dependent on the current locale.)
 (?m) for re.MULTILINE  (Makes ^ and $ match before and after newlines)
 (?s) for re.DOTALL  (Makes . match newlines)
 (?u) for re.UNICODE (Make \w, \W, \b, \B, \d, \D, \s and \S dependent on the Unicode character properties database.)
 (?x) for re.VERBOSE

For example, the following pattern ignores case (case insensitive):

 re.search ("(?i)password", string)

The flags can be combined. The following ignores case and matches DOTALL:

 re.search ("(?is)username.*?password", string)

Parse a simple date

This format is used by the `motion` command. This parses the date from filenames in this example format:

   02-20070505085051-04.jpg

The return format is a sequence the same as used in the standard Python library time module. This is pretty trivial, but shows using named sub-expressions.

def date_from_filename (filename):
    m = re.match(".*?[0-9]{2}-(?P<YEAR>[0-9]{4})(?P<MONTH>[0-9]{2})(?P<DAY>[0-9]{2})(?P<HOUR>[0-9]{2})(?P<MIN>[0-9]{2})(?P<SEC>[0-9]{2})-(?P<SEQ>[0-9]{2}).*?", filename)
    if m is None:
        print "Bad date parse in filename:", filename
        return None
    day   = int(m.group('DAY'))
    month = int(m.group('MONTH'))
    year  = int(m.group('YEAR'))
    hour  = int(m.group('HOUR'))
    min   = int(m.group('MIN'))
    sec   = int(m.group('SEC'))
    dts = (year, month, day, hour, min, sec, 0, 1, -1)
    return dts

Common Short RegEx Patterns

These are some regex patterns that I have found come up often. These examples assume a string, called page, that could, for instance, be an HTML document downloaded from the web. They will return a list of all non-overlapping matches found on the page.

fin = urllib.urlopen('http://www.example.com/index.html')
lines = fin.readlines()
fin.close()
page = str(lines)

email regex pattern

It's almost impossible to match a legal email address with a small, concise regex, but this one will match most.

emails = re.findall('[a-zA-Z0-9+_\-\.]+@[0-9a-zA-Z][.-0-9a-zA-Z]*.[a-zA-Z]+', page)

URL regex pattern

urls = re.findall('http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+', page)

IP address regex pattern

ips = re.findall('(?:[\d]{1,3})\.(?:[\d]{1,3})\.(?:[\d]{1,3})\.(?:[\d]{1,3})', page)