Skip to content

Instantly share code, notes, and snippets.

@taylorwood
Created May 14, 2018 20:06
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save taylorwood/239e7c25e55b41a7e321780c4a5e3a0b to your computer and use it in GitHub Desktop.
Save taylorwood/239e7c25e55b41a7e321780c4a5e3a0b to your computer and use it in GitHub Desktop.
Clojure Instaparse examples
;; "human" date/time format parsing
(def human-time-parser
(insta/parser
"S = H (':' M)? ' '? P? (' ' Z)?
H = #'[1-9]' | #'1[0-2]'
M = #'0[0-9]' | #'[1-5][0-9]'
P = AM | PM
AM = 'A' 'M'?
PM = 'P' 'M'?
Z = 'EST' | 'ET' | 'CST' | 'CT' | 'PST' | 'PT' | 'MST' | 'MT'"
:string-ci true))
(defn interpret-parse [tree]
(reduce (fn [acc elem]
(if (vector? elem)
(let [[tag & vals] elem]
(case tag
:H (assoc acc :hour (Integer/parseInt (first vals)))
:M (assoc acc :minute (Integer/parseInt (first vals)))
:P (assoc acc :period (ffirst vals))
:Z (assoc acc :timezone (first vals))
acc))
acc))
{}
tree))
(defn parse->date-time [date {:keys [hour minute period timezone]
:or {minute 0 period :PM}}]
(let [hour (case period ;; convert 12- to 24-hour time
:AM (if (= 12 hour) 0 hour)
:PM (if (< 0 hour 11)
(+ 12 hour)
hour))
tz (condp #(cs/starts-with? %2 %1) (or timezone "CST")
"C" (time/time-zone-for-id "US/Central")
"E" (time/time-zone-for-id "US/Eastern")
"P" (time/time-zone-for-id "US/Pacific")
"M" (time/time-zone-for-id "US/Mountain"))]
(-> (time/with-time-at-start-of-day date)
(.withHourOfDay hour)
(.withMinuteOfHour minute)
(time/from-time-zone tz))))
(def test-inputs
["10:01 am est"
"12 am"
"12 P CST"
"1am"
"2p PT"
"11:11p"
"1:00"])
(sequence
(comp
(map human-time-parser)
(map interpret-parse)
(map #(parse->date-time (time/now) %)))
test-inputs)
;; bowling scores
(def bowling-score-parser
(insta/parser
"S = F F F F F F F F F 10TH
F = OPEN | CLOSED
OPEN = ROLL ROLL
CLOSED = STRIKE | SPARE
10TH = OPEN |
SPARE (STRIKE | ROLL) |
STRIKE (SPARE | ROLL ROLL) |
STRIKE STRIKE (STRIKE | ROLL)
STRIKE = 'X'
SPARE = ROLL '/'
ROLL = PINS | MISS
PINS = #'[1-9]'
MISS = '-'"))
(bowling-score-parser "XXXXX6/XX7/XX5")
(bowling-score-parser "XXXXXXXXXXXX")
(bowling-score-parser "XXXXXXXXXX-/")
(bowling-score-parser "XXXXXXXXX--")
(bowling-score-parser "9-9-9-9-9-9-9-9-9-9-")
(bowling-score-parser "X7/9-X-88/-6XXX81")
(bowling-score-parser "X7/9-X-88/-6XX-/X")
(bowling-score-parser "X-/X5-8/9-X811-4/X")
(bowling-score-parser "6271X9-8/XX3572-/X")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment