Created
February 18, 2022 17:15
-
-
Save IGJoshua/09c0e4fcd7e496a611bc8724fce96e0c to your computer and use it in GitHub Desktop.
Cond expressions to bind regex capture groups
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
| (require '[clojure.spec.alpha :as s]) | |
| (defn- regex-cond-helper | |
| [expr-sym clauses default] | |
| (if-not (empty? clauses) | |
| (let [inner-clause (regex-cond-helper expr-sym (rest clauses) default) | |
| {:keys [regex bindings body] :as clause} (first clauses) | |
| regex (case (first regex) | |
| :regex (second regex) | |
| :else `(re-pattern ~(second regex))) | |
| binding (if (empty? bindings) | |
| (gensym "_") | |
| (into `[_#] bindings))] | |
| `(if-let [~binding (re-find ~regex ~expr-sym)] | |
| (do ~@body) | |
| ~inner-clause)) | |
| `(do ~@(second (second default))))) | |
| (s/def ::regex-cond-clause (s/cat :regex (s/or :regex (partial instance? java.util.regex.Pattern) | |
| :else any?) | |
| :bindings (s/coll-of symbol? | |
| :kind vector?) | |
| :body (s/* any?))) | |
| (s/def ::regex-cond-args (s/cat :expr any? | |
| :clauses (s/* (s/spec ::regex-cond-clause)) | |
| :default (s/? (s/cat :separator (partial = :default) | |
| :default (s/* any?))))) | |
| (defmacro regex-cond | |
| "Attempts to match a string against a set of regexes in sequence. | |
| Clauses are of the form | |
| (regex-expr bindings body*) | |
| The regex-expr may be either a regex literal or any expression that | |
| evaluates to something that can be used with [[re-pattern]]. | |
| The bindings is a vector of simple symbols which match each capture | |
| group bound from the regex. | |
| The body is any number of expressions to be evaluated when a regex | |
| matches. | |
| After all the clauses, a final keyword `:default` followed by any | |
| number of expressions to be evaluated when no regex matches is | |
| allowed." | |
| {:arglists '([expr] | |
| [expr clauses*] | |
| [expr clauses* & default]) | |
| :style/indent [:defn [:defn]]} | |
| [& args] | |
| (let [{:keys [expr clauses default]} (s/conform ::regex-cond-args args) | |
| expr-sym (gensym)] | |
| `(let [~expr-sym ~expr] | |
| ~(regex-cond-helper expr-sym clauses default)))) | |
| (s/fdef regex-cond | |
| :args ::regex-cond-args) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment