Skip to content

Commit cdfcf47

Browse files
committed
Refine testcases and and escape ranges including path separator literals.
1 parent 95b4ccf commit cdfcf47

File tree

3 files changed

+23
-21
lines changed

3 files changed

+23
-21
lines changed

Lib/fnmatch.py

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,9 @@ def _translate(pat, star, question_mark):
8787
res = []
8888
add = res.append
8989
star_indices = []
90-
inside_range=False
90+
inside_range = False
91+
add_negative_lookahead = False
92+
question_mark_char = re.sub(r'\[|\]|\^', '', question_mark)
9193

9294
i, n = 0, len(pat)
9395
while i < n:
@@ -136,21 +138,13 @@ def _translate(pat, star, question_mark):
136138
if chunks[k-1][-1] > chunks[k][0]:
137139
chunks[k-1] = chunks[k-1][:-1] + chunks[k][1:]
138140
del chunks[k]
139-
140141
if len(chunks)>1:
141-
char_range=set(range(ord(chunks[0][-1]), ord(chunks[-1][0])))
142-
143-
question_mark_char=question_mark.replace('\\', '').replace('[', '').replace(']', '').replace('^', '')
144-
question_mark_char=set(map(ord, question_mark_char))
145-
146-
if question_mark_char.intersection(char_range):
147-
inside_range=True
148-
142+
if question_mark_char:
143+
inside_range = chunks[0][-1] <= question_mark_char <= chunks[-1][0]
149144
# Escape backslashes and hyphens for set difference (--).
150145
# Hyphens that create ranges shouldn't be escaped.
151146
stuff = '-'.join(s.replace('\\', r'\\').replace('-', r'\-')
152147
for s in chunks)
153-
154148
i = j+1
155149
if not stuff:
156150
# Empty range: never match.
@@ -159,14 +153,22 @@ def _translate(pat, star, question_mark):
159153
# Negated empty range: match any character.
160154
add(question_mark)
161155
else:
156+
negative_lookahead=''
162157
if question_mark != '.' and inside_range:
163-
add(f'(?={question_mark})')
158+
add_negative_lookahead = True
159+
negative_lookahead = negative_lookahead + question_mark_char
164160
# Escape set operations (&&, ~~ and ||).
165161
stuff = _re_setops_sub(r'\\\1', stuff)
166162
if stuff[0] == '!':
163+
if question_mark_char not in stuff and question_mark != '.':
164+
add_negative_lookahead = True
165+
negative_lookahead = negative_lookahead + question_mark_char
167166
stuff = '^' + stuff[1:]
168-
elif stuff[0] in ('^', '['):
167+
elif stuff[0] in ('^', '[', question_mark_char):
169168
stuff = '\\' + stuff
169+
if add_negative_lookahead:
170+
add(f'(?![{negative_lookahead}])')
171+
add_negative_lookahead = False
170172
add(f'[{stuff}]')
171173
else:
172174
add(_re_escape(c))

Lib/glob.py

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -281,8 +281,6 @@ def translate(pat, *, recursive=False, include_hidden=False, seps=None):
281281
seps = (os.path.sep, os.path.altsep)
282282
else:
283283
seps = os.path.sep
284-
285-
286284
escaped_seps = ''.join(map(re.escape, seps))
287285
any_sep = f'[{escaped_seps}]' if len(seps) > 1 else escaped_seps
288286
not_sep = f'[^{escaped_seps}]'
@@ -313,12 +311,9 @@ def translate(pat, *, recursive=False, include_hidden=False, seps=None):
313311
if part:
314312
if not include_hidden and part[0] in '*?':
315313
results.append(r'(?!\.)')
316-
317314
results.extend(fnmatch._translate(part, f'{not_sep}*', not_sep)[0])
318-
319315
if idx < last_part_idx:
320316
results.append(any_sep)
321-
322317
res = ''.join(results)
323318
return fr'(?s:{res})\Z'
324319

Lib/test/test_glob.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -513,9 +513,14 @@ def fn(pat):
513513
return glob.translate(pat, recursive=True, include_hidden=True, seps=['/', '\\'])
514514
self.assertEqual(fn('foo/bar\\baz'), r'(?s:foo[/\\]bar[/\\]baz)\Z')
515515
self.assertEqual(fn('**/*'), r'(?s:(?:.+[/\\])?[^/\\]+)\Z')
516-
517-
self.assertEqual(fn('foo[%-0]bar'), r'(?s:foo(?=[^/\\])[%-0]bar)\Z')
518-
516+
self.assertEqual(fn('foo[!a]bar'), r'(?s:foo(?![/\\])[^a]bar)\Z')
517+
self.assertEqual(fn('foo[%-0]bar'), r'(?s:foo(?![/\\])[%-0]bar)\Z')
518+
self.assertEqual(fn('foo[%-0][1-9]bar'), r'(?s:foo(?![/\\])[%-0][1-9]bar)\Z')
519+
self.assertEqual(fn('foo[0-%]bar'), r'(?s:foo(?!)bar)\Z')
520+
self.assertEqual(fn('foo[^-'), r'(?s:foo\[\^\-)\Z')
521+
self.assertEqual(fn('foo[/-/]bar'), r'(?s:foo\[[/\\]\-[/\\]\]bar)\Z')
522+
self.assertEqual(fn('foo[%-/]bar'), r'(?s:foo\[%\-[/\\]\]bar)\Z')
523+
self.assertEqual(fn('foo[/]bar'), r'(?s:foo\[[/\\]\]bar)\Z')
519524

520525
if __name__ == "__main__":
521526
unittest.main()

0 commit comments

Comments
 (0)