diff -r b10a9d4f08eb Doc/library/glob.rst --- a/Doc/library/glob.rst Mon Mar 11 09:43:25 2013 +0200 +++ b/Doc/library/glob.rst Mon Mar 11 16:16:21 2013 +0200 @@ -40,6 +40,17 @@ without actually storing them all simultaneously. +.. function:: escape(pathname) + + Escape all special characters (``'?'``, ``'*'`` and ``'['``). + This is useful if you want to match an arbitrary literal string that may + have special characters in it. Do not escape special characters in the + drive/UNC sharepoint (i.e. on Windows ``escape('//?/c:/Quo vadis?.txt')`` + returns ``'//?/c:/Quo vadis[?].txt'``). + + .. versionadded:: 3.4 + + For example, consider a directory containing only the following files: :file:`1.gif`, :file:`2.txt`, and :file:`card.gif`. :func:`glob` will produce the following results. Notice how any leading components of the path are diff -r b10a9d4f08eb Lib/glob.py --- a/Lib/glob.py Mon Mar 11 09:43:25 2013 +0200 +++ b/Lib/glob.py Mon Mar 11 16:16:21 2013 +0200 @@ -79,8 +79,8 @@ return [] -magic_check = re.compile('[*?[]') -magic_check_bytes = re.compile(b'[*?[]') +magic_check = re.compile('([*?[])') +magic_check_bytes = re.compile(b'([*?[])') def has_magic(s): if isinstance(s, bytes): @@ -91,3 +91,17 @@ def _ishidden(path): return path[0] in ('.', b'.'[0]) + +def escape(pathname): + """Escape all special characters. + """ + # Escaping is done by wrapping any of "*?[" between square brackets. + # Metacharacters do not work in the drive part and shouldn't be escaped. + drive, _ = os.path.splitdrive(pathname) + if drive: + pathname = pathname[len(drive)] + if isinstance(pathname, bytes): + pathname = magic_check_bytes.sub(br'[\1]', pathname) + else: + pathname = magic_check.sub(r'[\1]', pathname) + return drive + pathname diff -r b10a9d4f08eb Lib/test/test_glob.py --- a/Lib/test/test_glob.py Mon Mar 11 09:43:25 2013 +0200 +++ b/Lib/test/test_glob.py Mon Mar 11 16:16:21 2013 +0200 @@ -169,6 +169,21 @@ eq(glob.glob('\\\\*\\*\\'), []) eq(glob.glob(b'\\\\*\\*\\'), []) + def test_escape(self): + def check(arg, expected): + self.assertEqual(glob.escape(arg), expected) + self.assertEqual(glob.escape(os.fsencode(arg)), + os.fsencode(expected)) + check('[', '[[]') + check('?', '[?]') + check('*', '[*]') + if sys.platform == 'win32': + check('?:?', '?:[?]') + check('*:*', '*:[*]') + check('\\\\?\\c:\\?', '\\\\?\\c:\\[?]') + check('\\\\*\\*\\*', '\\\\*\\*\\[*]') + check('//?/c:/?', '//?/c:/[?]') + check('//*/*/*', '//*/*/[*]') def test_main(): run_unittest(GlobTests)