problem with regular expression?

kbaum at es.com kbaum at es.com
Fri May 14 17:00:32 EDT 2004


I'm trying to scan a (binary) file for a string matching a particular
pattern, and am getting unexpected results.  I don't know if this is a bug
or just my own misunderstanding of regular expressions.

The string I'm searching for is a "versioned file name" of the form: 
"AMS_epXXXx.flt", where 'XXX' is 1 to 3 numerals, the 'x' is lower case 'a-z', 
and the '_' and 'ep' are each optional.  In other words, the following are 
examples that match:

	AMSep12a.flt
	ams_ep101b.flt
	ams_123z.flt
	ams12z.flt

The regular expression pattern I'm using is:

	prefix='ams'
	pat = re.compile(prefix + r'(?:(_)?(ep)?([0-9]{1,3}[a-z])\.flt)', re.I)


I'm using the parenthesized groups to conditionally process the match, i.e.,
if there is no '_' or 'ep' in the name, I still want the match but handle
it differently.  In my pattern above, group 1 is the (_) group, group 2 is 
the (ep) group, and group 3 is the "version string" group.

The problem I'm having is that the following string of bytes (hex data from
a file I'm scanning) returns a '_' in match group 1 even though it is 
outside the filename pattern that is properly detected:

Here's a code snippet to illustrate:


#============================================================================
import binascii, re

prefix = 'ams'
#...
pat = re.compile(prefix + r'(?:(_)?(ep)?([0-9]{1,3}[a-z])\.flt)', re.I)

#...scan file...

#-------------------------
# bytes in problem string (note that this section is arbitrary and not part 
# of the actual problem; it's just my attempt at converting the output of
# a hexdump file utility into a python string so as to illustrate the problem
# in a self-contained test case:

# problem data in file:
#
# 000a 0004 0002 0020 414d 535f 6a75 6c00
# 0000 0000 0000 0000 0000 0000 0000 0000
# 0000 0000 000a 0004 003f 00d8 414d 5365
# 7031 3031 692e 666c 7400 0000 0000 0000
# 000a 0004 0002 0020 414d 535f 6a75 6c00  ....... AMS_jul.
# 0000 0000 0000 0000 0000 0000 0000 0000  ................
# 0000 0000 000a 0004 003f 00d8 414d 5365  .........?..AMSe
# 7031 3031 692e 666c 7400 0000 0000 0000  p101i.flt.......

bytes = '000a000400020020414d535f6a756c000000000000000000000000000000000000000000000a0004003f00d8414d536570313031692e666c7400000000000000'

ascii = binascii.a2b_hex(bytes)
#-------------------------

m = pat.search(ascii)
print m.groups()
print m.span(0), m.span(1), m.span(2), m.span(3)

#output: 	('_', 'ep', '101i')
#		(44, 57) (11, 12) (47, 49) (49, 53)
#
# Note that the '_' reported at position 11 in "AMS_jul" is outside the 
# range of the "real" matched string "AMSep101i.flt" at positions (44-57)!




More information about the Python-list mailing list