summaryrefslogtreecommitdiffstats
path: root/Lib
diff options
context:
space:
mode:
authorFredrik Lundh <fredrik@pythonware.com>2000-07-03 18:44:21 (GMT)
committerFredrik Lundh <fredrik@pythonware.com>2000-07-03 18:44:21 (GMT)
commit6f013982366154ce570f69b6117dbcc6b1d5d89a (patch)
tree00f3bcae833f7bbcb15ba1a22ef2bdac3c148033 /Lib
parent40c48685a2b16dc7fdccd82fe1d927e52ed5e3db (diff)
downloadcpython-6f013982366154ce570f69b6117dbcc6b1d5d89a.zip
cpython-6f013982366154ce570f69b6117dbcc6b1d5d89a.tar.gz
cpython-6f013982366154ce570f69b6117dbcc6b1d5d89a.tar.bz2
- added lookbehind support (?<=pattern), (?<!pattern).
the pattern must have a fixed width. - got rid of array-module dependencies; the match pro- gram is now stored inside the pattern object, rather than in an extra string buffer. - cleaned up a various of potential leaks, api abuses, and other minors in the engine module. - use mal's new isalnum macro, rather than my own work- around. - untabified test_sre.py. seems like I removed a couple of trailing spaces in the process...
Diffstat (limited to 'Lib')
-rw-r--r--Lib/sre_compile.py29
-rw-r--r--Lib/sre_parse.py12
-rw-r--r--Lib/test/test_sre.py50
3 files changed, 51 insertions, 40 deletions
diff --git a/Lib/sre_compile.py b/Lib/sre_compile.py
index 36986eb..701b267 100644
--- a/Lib/sre_compile.py
+++ b/Lib/sre_compile.py
@@ -10,18 +10,10 @@
# other compatibility work.
#
-import array
import _sre
from sre_constants import *
-# find an array type code that matches the engine's code size
-for WORDSIZE in "Hil":
- if len(array.array(WORDSIZE, [0]).tostring()) == _sre.getcodesize():
- break
-else:
- raise RuntimeError, "cannot find a useable array type"
-
MAXCODE = 65535
def _charset(charset, fixup):
@@ -170,7 +162,20 @@ def _compile(code, pattern, flags):
emit((group-1)*2+1)
elif op in (SUCCESS, FAILURE):
emit(OPCODES[op])
- elif op in (ASSERT, ASSERT_NOT, CALL):
+ elif op in (ASSERT, ASSERT_NOT):
+ emit(OPCODES[op])
+ skip = len(code); emit(0)
+ if av[0] >= 0:
+ emit(0) # look ahead
+ else:
+ lo, hi = av[1].getwidth()
+ if lo != hi:
+ raise error, "look-behind requires fixed-width pattern"
+ emit(lo) # look behind
+ _compile(code, av[1], flags)
+ emit(OPCODES[SUCCESS])
+ code[skip] = len(code) - skip
+ elif op is CALL:
emit(OPCODES[op])
skip = len(code); emit(0)
_compile(code, av, flags)
@@ -305,7 +310,7 @@ def compile(p, flags=0):
indexgroup[i] = k
return _sre.compile(
- pattern, flags,
- array.array(WORDSIZE, code).tostring(),
- p.pattern.groups-1, groupindex, indexgroup
+ pattern, flags, code,
+ p.pattern.groups-1,
+ groupindex, indexgroup
)
diff --git a/Lib/sre_parse.py b/Lib/sre_parse.py
index d78737f..07ab782 100644
--- a/Lib/sre_parse.py
+++ b/Lib/sre_parse.py
@@ -482,9 +482,15 @@ def _parse(source, state):
if source.next is None or source.next == ")":
break
source.get()
- elif source.next in ("=", "!"):
+ elif source.next in ("=", "!", "<"):
# lookahead assertions
char = source.get()
+ dir = 1
+ if char == "<":
+ if source.next not in ("=", "!"):
+ raise error, "syntax error"
+ dir = -1 # lookbehind
+ char = source.get()
b = []
while 1:
p = _parse(source, state)
@@ -493,9 +499,9 @@ def _parse(source, state):
b.append(p)
p = _branch(state, b)
if char == "=":
- subpattern.append((ASSERT, p))
+ subpattern.append((ASSERT, (dir, p)))
else:
- subpattern.append((ASSERT_NOT, p))
+ subpattern.append((ASSERT_NOT, (dir, p)))
break
elif source.match("|"):
b.append(p)
diff --git a/Lib/test/test_sre.py b/Lib/test/test_sre.py
index dc42ed1..a22c51a 100644
--- a/Lib/test/test_sre.py
+++ b/Lib/test/test_sre.py
@@ -35,20 +35,20 @@ if verbose:
try:
assert sre.sub("(?i)b+", "x", "bbbb BBBB") == 'x x'
-
+
def bump_num(matchobj):
int_value = int(matchobj.group(0))
return str(int_value + 1)
assert sre.sub(r'\d+', bump_num, '08.2 -2 23x99y') == '9.3 -3 24x100y'
assert sre.sub(r'\d+', bump_num, '08.2 -2 23x99y', 3) == '9.3 -3 23x99y'
-
+
assert sre.sub('.', lambda m: r"\n", 'x') == '\\n'
assert sre.sub('.', r"\n", 'x') == '\n'
s = r"\1\1"
assert sre.sub('(.)', s, 'x') == 'xx'
- assert sre.sub('(.)', sre.escape(s), 'x') == s
+ assert sre.sub('(.)', sre.escape(s), 'x') == s
assert sre.sub('(.)', lambda m: s, 'x') == s
assert sre.sub('(?P<a>x)', '\g<a>\g<a>', 'xx') == 'xxxx'
@@ -144,7 +144,7 @@ except AssertionError:
if verbose:
print 'Running tests on sre.split'
-
+
try:
assert sre.split(":", ":a:b::c") == ['', 'a', 'b', '', 'c']
assert sre.split(":*", ":a:b::c") == ['', 'a', 'b', 'c']
@@ -164,7 +164,7 @@ try:
assert sre.split(':', 'a:b:c:d', 2) == ['a', 'b', 'c:d']
assert sre.split("(:)", ":a:b::c", 2) == ['', ':', 'a', ':', 'b::c']
- assert sre.split("(:*)", ":a:b::c", 2) == ['', ':', 'a', ':', 'b::c']
+ assert sre.split("(:*)", ":a:b::c", 2) == ['', ':', 'a', ':', 'b::c']
except AssertionError:
raise TestFailed, "qualified sre.split"
@@ -186,29 +186,29 @@ if verbose:
try:
# No groups at all
- m = sre.match('a', 'a') ; assert m.groups() == ()
+ m = sre.match('a', 'a') ; assert m.groups() == ()
# A single group
- m = sre.match('(a)', 'a') ; assert m.groups() == ('a',)
+ m = sre.match('(a)', 'a') ; assert m.groups() == ('a',)
pat = sre.compile('((a)|(b))(c)?')
- assert pat.match('a').groups() == ('a', 'a', None, None)
- assert pat.match('b').groups() == ('b', None, 'b', None)
- assert pat.match('ac').groups() == ('a', 'a', None, 'c')
- assert pat.match('bc').groups() == ('b', None, 'b', 'c')
- assert pat.match('bc').groups("") == ('b', "", 'b', 'c')
+ assert pat.match('a').groups() == ('a', 'a', None, None)
+ assert pat.match('b').groups() == ('b', None, 'b', None)
+ assert pat.match('ac').groups() == ('a', 'a', None, 'c')
+ assert pat.match('bc').groups() == ('b', None, 'b', 'c')
+ assert pat.match('bc').groups("") == ('b', "", 'b', 'c')
except AssertionError:
raise TestFailed, "match .groups() method"
try:
# A single group
- m = sre.match('(a)', 'a')
- assert m.group(0) == 'a' ; assert m.group(0) == 'a'
+ m = sre.match('(a)', 'a')
+ assert m.group(0) == 'a' ; assert m.group(0) == 'a'
assert m.group(1) == 'a' ; assert m.group(1, 1) == ('a', 'a')
pat = sre.compile('(?:(?P<a1>a)|(?P<b2>b))(?P<c3>c)?')
- assert pat.match('a').group(1, 2, 3) == ('a', None, None)
- assert pat.match('b').group('a1', 'b2', 'c3') == (None, 'b', None)
- assert pat.match('ac').group(1, 'b2', 3) == ('a', None, 'c')
+ assert pat.match('a').group(1, 2, 3) == ('a', None, None)
+ assert pat.match('b').group('a1', 'b2', 'c3') == (None, 'b', None)
+ assert pat.match('ac').group(1, 'b2', 3) == ('a', None, 'c')
except AssertionError:
raise TestFailed, "match .group() method"
@@ -252,10 +252,10 @@ try:
assert sre.I == sre.IGNORECASE
assert sre.L == sre.LOCALE
assert sre.M == sre.MULTILINE
- assert sre.S == sre.DOTALL
- assert sre.X == sre.VERBOSE
- assert sre.T == sre.TEMPLATE
- assert sre.U == sre.UNICODE
+ assert sre.S == sre.DOTALL
+ assert sre.X == sre.VERBOSE
+ assert sre.T == sre.TEMPLATE
+ assert sre.U == sre.UNICODE
except AssertionError:
raise TestFailed, 're module constants'
@@ -272,7 +272,7 @@ if verbose:
else:
# To save time, only run the first and last 10 tests
#tests = tests[:10] + tests[-10:]
- pass
+ pass
for t in tests:
sys.stdout.flush()
@@ -280,7 +280,7 @@ for t in tests:
if len(t)==5:
pattern, s, outcome, repl, expected = t
elif len(t)==3:
- pattern, s, outcome = t
+ pattern, s, outcome = t
else:
raise ValueError, ('Test tuples should have 3 or 5 fields',t)
@@ -288,7 +288,7 @@ for t in tests:
obj=sre.compile(pattern)
except sre.error:
if outcome==SYNTAX_ERROR: pass # Expected a syntax error
- else:
+ else:
print '=== Syntax error:', t
except KeyboardInterrupt: raise KeyboardInterrupt
except:
@@ -356,7 +356,7 @@ for t in tests:
# of the match and see if it still succeeds. \B will
# break (because it won't match at the end or start of a
# string), so we'll ignore patterns that feature it.
-
+
if pattern[:2]!='\\B' and pattern[-2:]!='\\B':
obj=sre.compile(pattern)
result=obj.search(s, result.start(0), result.end(0)+1)