Last active
November 8, 2020 10:51
-
-
Save Mikhail-Borisov/137b100aef83ed502f40bc99f22d6d00 to your computer and use it in GitHub Desktop.
Clojure macro for regex that returns named capture groups as a map
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(defmacro mk-named-regex-fn | |
"Given an expression that returns a string returns a function | |
that given a string returns nil if pattern did not match | |
and a map of named groups if pattern matches. | |
Usage: ((regex \"(?<name>[a-zA-Z]+)\") \"John\") => {\"name\" \"John\"}" | |
[regex-string-expression] | |
(let [regex-string (eval regex-string-expression) | |
re-group-regex #"(?<!\\)(?:\\\\)*\((?:\?<(\w+)>|[^?])" | |
pattern (re-pattern regex-string) | |
group-names (mapv second (re-seq re-group-regex regex-string)) | |
group-length (count group-names)] | |
`(fn [s#] | |
(let [matcher# (re-matcher ~pattern s#)] | |
(if (.matches matcher#) | |
(loop [groups# (transient {}) | |
n# 0] | |
(if (< n# ~group-length) | |
(let [inc-n# (inc n#) | |
group-name# (get ~group-names n#)] | |
(recur (assoc! groups# group-name# (.group matcher# inc-n#)) | |
inc-n#)) | |
(persistent! groups#))) | |
nil))))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment