Last active
May 25, 2016 20:33
-
-
Save ggeoffrey/6066f93555c022e25c0efa4113f579e9 to your computer and use it in GitHub Desktop.
This is clean and elegant … I guess… Way better then the first version.
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
(defn re-extract | |
"Try to re-find all given regexps until one matches. | |
nil if none matches." | |
[value & regexps] | |
(cond | |
(nil? value) nil ;; safe fallback | |
(empty? regexps) nil ;; no params or no more regexps to try | |
:else (let [pattern (first regexps) ;; take the first one | |
extracted (re-find pattern value)] ;; search for it | |
(cond | |
(string? extracted) extracted ;; a string mean "found" | |
:else ;; tail-call recurtion on the rest of the list | |
(recur value (rest regexps)))))) | |
(defmacro safe-call | |
"Simply wrap the call in a try/catch block. | |
Return nil if something horrible happens." | |
[f body] | |
`(try | |
(~f ~body) | |
(catch Exception e# | |
nil))) | |
(defmacro with-parse | |
"Take a list of pairs like: | |
[value1 parsing-function-1 | |
value2 parsing-function-2] | |
and create a binding like: | |
[value1 (parsing-function-1 value1) | |
value2 (parsing-function-2 value2)] " | |
[list body] | |
(let [pairs (partition 2 list) ;; make pairs of '(symbol symbol) | |
application (into [] ;; put into a vector | |
;; the flattened mapping of 'pairs' | |
(mapcat (fn [[value# function#]] | |
;; return a vector for the let binding | |
[value# `(safe-call ~function# ~value#)]) | |
pairs))] | |
;; write to the AST | |
`(let ~application ~body))) | |
;; Optional | |
(defmacro parsing-with | |
"Shorthand for with-parse when there's only one parsing function." | |
[function values body] | |
;; create pairs like (interpose function values) | |
;; but for the last value too | |
(let [bindings (into [] ;; into a vector | |
(mapcat ;; put the flattened | |
#(vector % function) ;; pairs | |
values))] ;; of values | |
;; write to AST | |
`(with-parse ~bindings ~body))) | |
(defn compare-by-numeric-priority | |
"Compare two strings by their numeric priority | |
if they both start by a number. Otherwise compare | |
by alphabetical order." | |
[str1 str2] | |
(let [patterns [#"^\d+\.\d+" #"^\d+"] ;; what is a number? | |
num1 (apply re-extract str1 patterns) ;; try to find it in the 1st | |
num2 (apply re-extract str2 patterns)] ;; and in the second | |
(cond | |
(or (nil? num1) ;; if one of them doesn't start with a number | |
(nil? num2)) (compare str1 str2) ;; simply compare them | |
:else ;; by using the parsed version | |
(parsing-with Double/parseDouble | |
[num1 num2] | |
;; compare them | |
(compare num1 num2))))) | |
(def list-of-headers '("foo" "bar" "3.bazz" "3.2 bazz2" "a")) | |
(sort compare-by-numeric-priority list-of-headers) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment