diff options
author | Tim Peters <tim.peters@gmail.com> | 2004-08-19 14:06:20 (GMT) |
---|---|---|
committer | Tim Peters <tim.peters@gmail.com> | 2004-08-19 14:06:20 (GMT) |
commit | dc5de3bab2f6a202b6cd4b94ae9ac8b46e804caa (patch) | |
tree | 88e99505a604941754f8efaa4ea5ba2bd31ecce0 | |
parent | 336e85f56a87f2216855ca8a5771755f480ae7db (diff) | |
download | cpython-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.py | 60 |
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 |