Skip to content

Instantly share code, notes, and snippets.

@jkk
Created March 29, 2010 05:27
Show Gist options
  • Select an option

  • Save jkk/347462 to your computer and use it in GitHub Desktop.

Select an option

Save jkk/347462 to your computer and use it in GitHub Desktop.
;; TODO: make Windows-friendly; extensive tests
(defn- glob->regex [s]
"Takes a glob-format string and returns a regex."
(let [stream (java.io.StringReader. s)]
(loop [i (.read stream)
re ""
curly-depth 0]
(let [c (char i)
j (.read stream)]
(cond
(= i -1) (re-pattern (str (if (= \. (first s)) "" "(?=[^\\.])") re))
(= c \\) (recur (.read stream) (str re c (char j)) curly-depth)
(= c \/) (recur j (str re (if (= \. (char j)) c "/(?=[^\\.])"))
curly-depth)
(= c \*) (recur j (str re "[^/]*") curly-depth)
(= c \?) (recur j (str re "[^/]") curly-depth)
(= c \{) (recur j (str re \() (inc curly-depth))
(= c \}) (recur j (str re \)) (dec curly-depth))
(and (= c \,) (< 0 curly-depth)) (recur j (str re \|) curly-depth)
(#{\. \( \) \| \+ \^ \$ \@ \%} c) (recur j (str re \\ c) curly-depth)
:else (recur j (str re c) curly-depth))))))
(defn- glob* [pattern]
"Returns a list of java.io.File instances that match the given glob pattern"
(let [abs-path? (= \/ (first pattern))
start-dir (java.io.File. (if abs-path? "/" "."))
patterns (map glob->regex
(.split (if abs-path? (subs pattern 1) pattern) "/"))
expand (fn [re dir]
(filter #(re-matches re (.getName %)) (.listFiles dir)))]
(reduce #(mapcat (partial expand %2) %1) [start-dir] patterns)))
(defn glob [pattern]
"Returns a list of java.io.File instances that match one or more glob
patterns, separated by spaces. E.g., \"*.jpg *.gif\". Ignores dot
files unless explicitly included. E.g., to match all files, \"* .*\""
(mapcat glob* (.split pattern " ")))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment