shellpattern.py 2.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162
  1. import os
  2. import re
  3. def translate(pat):
  4. """Translate a shell-style pattern to a regular expression.
  5. The pattern may include "**<sep>" (<sep> stands for the platform-specific path separator; "/" on POSIX systems) for
  6. matching zero or more directory levels and "*" for matching zero or more arbitrary characters with the exception of
  7. any path separator. Wrap meta-characters in brackets for a literal match (i.e. "[?]" to match the literal character
  8. "?").
  9. This function is derived from the "fnmatch" module distributed with the Python standard library.
  10. Copyright (C) 2001-2016 Python Software Foundation. All rights reserved.
  11. TODO: support {alt1,alt2} shell-style alternatives
  12. """
  13. sep = os.path.sep
  14. n = len(pat)
  15. i = 0
  16. res = ""
  17. while i < n:
  18. c = pat[i]
  19. i += 1
  20. if c == "*":
  21. if i + 1 < n and pat[i] == "*" and pat[i + 1] == sep:
  22. # **/ == wildcard for 0+ full (relative) directory names with trailing slashes; the forward slash stands
  23. # for the platform-specific path separator
  24. res += r"(?:[^\%s]*\%s)*" % (sep, sep)
  25. i += 2
  26. else:
  27. # * == wildcard for name parts (does not cross path separator)
  28. res += r"[^\%s]*" % sep
  29. elif c == "?":
  30. # ? == any single character excluding path separator
  31. res += r"[^\%s]" % sep
  32. elif c == "[":
  33. j = i
  34. if j < n and pat[j] == "!":
  35. j += 1
  36. if j < n and pat[j] == "]":
  37. j += 1
  38. while j < n and pat[j] != "]":
  39. j += 1
  40. if j >= n:
  41. res += "\\["
  42. else:
  43. stuff = pat[i:j].replace("\\", "\\\\")
  44. i = j + 1
  45. if stuff[0] == "!":
  46. stuff = "^" + stuff[1:]
  47. elif stuff[0] == "^":
  48. stuff = "\\" + stuff
  49. res += "[%s]" % stuff
  50. else:
  51. res += re.escape(c)
  52. return res + r"\Z(?ms)"