Skip to content

Instantly share code, notes, and snippets.

@eval
Last active March 21, 2024 15:44
Show Gist options
  • Save eval/504ebccdd784413e4f7f03369ffc97de to your computer and use it in GitHub Desktop.
Save eval/504ebccdd784413e4f7f03369ffc97de to your computer and use it in GitHub Desktop.
deps-try recipe to play around with the code from https://polar.sh/eval/posts/named-group-captures-in-clojure
;; Use this file with [deps-try](https://github.com/eval/deps-try)
;; $ docker run -it ghcr.io/eval/deps-try --recipe https://gist.github.com/eval/60989e7782397c1aff7a47978b1931d9
;; This work is licensed under [CC BY 4.0](http://creativecommons.org/licenses/by/4.0/)
(ns blog.re-named-captures
"Example code from https://polar.sh/eval/posts/named-group-captures-in-clojure (requires Java >= v20)."
(:require [clojure.string :as str]))
;; the regex from the blogpost
(def url-re
#"(?x)
#; match e.g. 'https://google.com:8000/search#fragment'
https?:// #; 'http://' or 'https://'
(?<host>[^:/]+) #; 'google.com'
(?:\: #; (optional) ':8000'
(?<port>[^/]+))? # '8000'
(?: #; (optional) '/search#fragment'
(?<path>/[^\#]*) #; '/search'
(?:\# #; (optional) '#fragment'
(?<fragment>.+))? #; 'fragment'
)?
")
(defn re-named-captures
"Yields a map of capture group names and data when `s` matches `re`.
Keywordizes group names by default. Supply `:keywordize-keys false` to suppress this behavior.
Otherwise provide `:group->key` to override how group names are turned into keys.
Examples:
(re-named-captures #\"(?<timestamp>\\d+),(?<author>)\" \"2022,eval\")
;; => {:timestamp \"2022\" :author \"eval\"}
"
([re s] (re-named-captures re s nil))
([re s & {:keys [keywordize-keys] :as options}]
(let [group->key (if (false? keywordize-keys) identity keyword)
{:keys [group->key]} (merge {:group->key group->key} options)]
(try
(let [^java.util.regex.Matcher matcher (re-matcher re s)]
(when (.find matcher)
(reduce (fn [acc gname]
(if-let [cap (.group matcher gname)]
(assoc acc (group->key gname) cap)
acc))
{} (keys (.namedGroups re)))))
(catch IllegalArgumentException _
(let [java-version (System/getProperty "java.version")]
(throw
(ex-info
(str "java.util.regex.Matcher/namedGroups is only supported on Java v20 and up "
"(found: " java-version ").") {}))))))))
;; TIP quick eval: place cursor at end of expression (e.g. at a comma)
;; and press Ctrl-c Ctrl-e
;; to submit: Ctrl-x Ctrl-m
;;
;; simple example
(re-named-captures url-re "Some url: https://google.com:443/search#results"),
;; suppress transforming key
(re-named-captures url-re "Some url: https://google.com:443/search#results"
:keywordize-keys false),
;; custom key transformation
(re-named-captures url-re "Some url: https://google.com:443/search#results"
:group->key str/upper-case),
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment