Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Finding a regular-expression-like sequence of values in a Clojure vector

Tags:

clojure

I am using the libpostal library to find an full address (street, city, state, and postal code) within a news article. libpostal when given input text:

There was an accident at 5 Main Street Boulder, CO 10566 -- which is at the corner of Wilson.

returns a vector:

[{:label "house", :value "there was an accident at 5"}
 {:label "road", :value "main street"} 
 {:label "city", :value "boulder"}
 {:label "state", :value "co"}
 {:label "postcode", :value "10566"}
 {:label "road", :value "which is at the corner of wilson."}

I am wondering if there is a clever way in Clojure to extract a sequence where the :label values occur in a sequence:

[road unit? level? po_box? city state postcode? country?]

where ? represents an optional value in the match.

like image 582
frank Avatar asked May 13 '26 04:05

frank


1 Answers

You could do this with clojure.spec. First define some specs that match your maps' :label values:

(defn has-label? [m label] (= label (:label m)))
(s/def ::city #(has-label? % "city"))
(s/def ::postcode #(has-label? % "postcode"))
(s/def ::state #(has-label? % "state"))
(s/def ::house #(has-label? % "house"))
(s/def ::road #(has-label? % "road"))

Then define a regex spec e.g. s/cat + s/?:

(s/def ::valid-seq
  (s/cat :road ::road
         :city (s/? ::city) ;; ? = zero or once
         :state ::state
         :zip (s/? ::postcode)))

Now you can conform or valid?-ate your sequences:

(s/conform ::valid-seq [{:label "road" :value "Damen"}
                        {:label "city" :value "Chicago"}
                        {:label "state" :value "IL"}])
=>
{:road {:label "road", :value "Damen"},
 :city {:label "city", :value "Chicago"},
 :state {:label "state", :value "IL"}}
;; this is also valid, missing an optional value in the middle
(s/conform ::valid-seq [{:label "road" :value "Damen"}
                        {:label "state" :value "IL"}
                        {:label "postcode" :value "60622"}])
=>
{:road {:label "road", :value "Damen"},
 :state {:label "state", :value "IL"},
 :zip {:label "postcode", :value "60622"}}
like image 76
Taylor Wood Avatar answered May 16 '26 06:05

Taylor Wood



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!