mirror of
https://github.com/python/cpython.git
synced 2025-08-04 08:59:19 +00:00
ellipsis_match(): Changed treatment of start- and end-of-string exact
matches to be symmetric. This makes the algorithm easier to understand.
This commit is contained in:
parent
336e85f56a
commit
dc5de3bab2
1 changed files with 36 additions and 26 deletions
|
@ -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.
|
||||
w = ws[0]
|
||||
if w:
|
||||
# An ellipsis didn't start `want`. We need to match exactly
|
||||
# at the start.
|
||||
if not got.startswith(w):
|
||||
return False
|
||||
pos = len(w)
|
||||
del ws[0]
|
||||
else:
|
||||
pos = 0
|
||||
|
||||
# Deal with exact matches possibly needed at one or both ends.
|
||||
startpos, endpos = 0, len(got)
|
||||
w = ws[0]
|
||||
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
|
||||
|
||||
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)
|
||||
startpos += 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])
|
||||
return True
|
||||
|
||||
######################################################################
|
||||
## 2. Example & DocTest
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue