Last active
December 15, 2017 14:52
-
-
Save rauhs/bd3aa598f8d818bcc076 to your computer and use it in GitHub Desktop.
Clojure named caputred Regex with application for duration parsing "4 weeks 8d 20h 2mins"
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
(defn re-named-groups | |
"Returns the groups from the most recent match/find. If there are no | |
nested groups, returns a string of the entire match. If there are | |
nested groups, returns a vector of the groups, the first element | |
being the entire match." | |
[^java.util.regex.Matcher m kw] | |
(let [gc (. m (groupCount))] | |
(if (zero? gc) | |
(. m (group)) | |
(into {} (map (fn[x] [x (. m (group (name x)))]) kw))))) | |
(defn re-named-matches | |
"Returns the match, if any, of string to pattern, using | |
java.util.regex.Matcher.matches(). Uses re-groups to return the | |
groups." | |
[^java.util.regex.Pattern re s kw] | |
(let [m (re-matcher re s)] | |
(when (. m (matches)) | |
(re-named-groups m kw)))) | |
(def ^:const PERIOD-RE | |
#"(?ix) # Allow comments & case insensitive | |
############## WEEKS ############# | |
( | |
\s* # Opt whitespace | |
(?<weeks>\d*.?\d+) # digit | |
\s* | |
(w) # w for week | |
(?:eeks?|) # but optional non-caputring group which might be empty | |
\s*(?:and|,|) # optional `,' and/or `and' | |
)? | |
############## DAYS ############# | |
( | |
\s* | |
(?<days>\d*.?\d+) | |
\s* | |
(d) | |
(?:ays?|) | |
\s*(?:and|,|) | |
)? | |
############## HOURS ############# | |
( | |
\s* | |
(?<hours>\d*.?\d+) | |
\s* | |
(h) | |
(?:ours?|) | |
\s*(?:and|,|) | |
)? | |
############## MINUTES ############# | |
( | |
\s* | |
(?<mins>\d*.?\d+) | |
\s* | |
(m) | |
(?:ins?|inutes?|) | |
\s*(?:and|,|)\s* | |
)? | |
############## Seconds ############# | |
( | |
\s* | |
(?<seconds>\d*.?\d+) | |
\s* | |
(s) | |
(?:ecs?|econds?|) | |
\s* | |
)? | |
\s* # Allow some final whitespace | |
") | |
(defn parse-period | |
"Parses a period string to a map which gives the :weeks :days :hours and :mins. | |
Return nil if it failed to parse. | |
(parse-duration \"5w 4 days 8mins\")" | |
[s] | |
(map-vals | |
#(if % (Double/parseDouble %) 0) | |
(re-named-matches PERIOD-RE s #{:days :hours :mins :weeks :seconds}))) | |
(defn period->secs | |
"Converts the period map from parse-period to seconds." | |
[s] | |
(if-let [{:keys [weeks days hours mins seconds]} (parse-period s)] | |
(+ | |
seconds | |
(* mins 60.) | |
(* hours 60. 60.) | |
(* days 60. 60. 24.) | |
(* weeks 60. 60. 24. 7.)))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment