summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTim Peters <tim.peters@gmail.com>2004-08-19 14:06:20 (GMT)
committerTim Peters <tim.peters@gmail.com>2004-08-19 14:06:20 (GMT)
commitdc5de3bab2f6a202b6cd4b94ae9ac8b46e804caa (patch)
tree88e99505a604941754f8efaa4ea5ba2bd31ecce0
parent336e85f56a87f2216855ca8a5771755f480ae7db (diff)
downloadcpython-dc5de3bab2f6a202b6cd4b94ae9ac8b46e804caa.zip
cpython-dc5de3bab2f6a202b6cd4b94ae9ac8b46e804caa.tar.gz
cpython-dc5de3bab2f6a202b6cd4b94ae9ac8b46e804caa.tar.bz2
ellipsis_match(): Changed treatment of start- and end-of-string exact
matches to be symmetric. This makes the algorithm easier to understand.
-rw-r--r--Lib/doctest.py60
1 files changed, 35 insertions, 25 deletions
diff --git a/Lib/doctest.py b/Lib/doctest.py
index 6c5679d..c7a183b 100644
--- a/Lib/doctest.py
+++ b/Lib/doctest.py
@@ -364,47 +364,57 @@ class _SpoofOut(StringIO):
# Worst-case linear-time ellipsis matching.
def ellipsis_match(want, got):
+ """
+ Essentially the only subtle case:
+ >>> ellipsis_match('aa...aa', 'aaa')
+ False
+ """
if ELLIPSIS_MARKER not in want:
return want == got
# Remove \n from ...\n, else the newline will be required,
# and (for example) ... on a line by itself can't match
# nothing gracefully.
want = want.replace(ELLIPSIS_MARKER + '\n', ELLIPSIS_MARKER)
+
# Find "the real" strings.
ws = want.split(ELLIPSIS_MARKER)
assert len(ws) >= 2
- # Match. In general, we only need to find the leftmost non-overlapping
- # match for each piece. "Real strings" at the start or end of `want`
- # are special cases.
+
+ # Deal with exact matches possibly needed at one or both ends.
+ startpos, endpos = 0, len(got)
w = ws[0]
- if w:
- # An ellipsis didn't start `want`. We need to match exactly
- # at the start.
- if not got.startswith(w):
+ if w: # starts with exact match
+ if got.startswith(w):
+ startpos = len(w)
+ del ws[0]
+ else:
+ return False
+ w = ws[-1]
+ if w: # ends with exact match
+ if got.endswith(w):
+ endpos -= len(w)
+ del ws[-1]
+ else:
return False
- pos = len(w)
- del ws[0]
- else:
- pos = 0
+ if startpos > endpos:
+ # Exact end matches required more characters than we have, as in
+ # ellipsis_match('aa...aa', 'aaa')
+ return False
+
+ # For the rest, we only need to find the leftmost non-overlapping
+ # match for each piece. If there's no overall match that way alone,
+ # there's no overall match period.
for w in ws:
# w may be '' at times, if there are consecutive ellipses, or
# due to an ellipsis at the start or end of `want`. That's OK.
- # Search for an empty string succeeds, and doesn't change pos.
- pos = got.find(w, pos)
- if pos < 0:
+ # Search for an empty string succeeds, and doesn't change startpos.
+ startpos = got.find(w, startpos, endpos)
+ if startpos < 0:
return False
- pos += len(w)
-
- # If `want` ended with an ellipsis, the tail matches anything.
- if ws[-1] == '':
- return True
- # Else `want` ended with a real string. If the last real match
- # exhausted `got`, we win.
- if pos == len(got):
- return True
- # Else maybe we matched the last real string too early.
- return got.endswith(ws[-1])
+ startpos += len(w)
+
+ return True
######################################################################
## 2. Example & DocTest