Last active
March 21, 2024 15:44
-
-
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
This file contains 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
;; 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