Skip to content

Instantly share code, notes, and snippets.

@IGJoshua
Created February 18, 2022 17:15
Show Gist options
  • Select an option

  • Save IGJoshua/09c0e4fcd7e496a611bc8724fce96e0c to your computer and use it in GitHub Desktop.

Select an option

Save IGJoshua/09c0e4fcd7e496a611bc8724fce96e0c to your computer and use it in GitHub Desktop.
Cond expressions to bind regex capture groups
(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