在Clojure中解析URL参数是指从URL的查询字符串(问号后面的部分)中提取键值对数据的过程。例如在URL http://example.com?name=John&age=30
中,查询字符串是 name=John&age=30
,需要解析为Clojure的map结构 {:name "John" :age "30"}
。
ring.util.codec
模块这是最常用的方法,Ring框架提供了专门的工具函数:
(require '[ring.util.codec :as codec])
;; 解析查询字符串
(def query-string "name=John&age=30")
(def params (codec/form-decode query-string))
;; => {"name" "John", "age" "30"}
;; 如果需要关键字作为键
(def params (->> query-string
codec/form-decode
(map (fn [[k v]] [(keyword k) v]))
(into {})))
;; => {:name "John", :age "30"}
clojure.string
手动解析对于简单情况,可以使用Clojure核心库:
(require '[clojure.string :as str])
(defn parse-params [query-string]
(->> (str/split query-string #"&")
(map #(str/split % #"="))
(map (fn [[k v]] [(keyword k) v]))
(into {})))
(parse-params "name=John&age=30")
;; => {:name "John", :age "30"}
如果参数包含URL编码字符(如空格编码为%20),需要先解码:
(require '[ring.util.codec :as codec])
(def encoded-query "name=John+Doe&city=New+York")
(def decoded (codec/form-decode encoded-query))
;; => {"name" "John Doe", "city" "New York"}
当URL中有重复键时(如?color=red&color=blue
),默认行为会覆盖值。如果需要保留所有值:
(defn parse-multi-params [query-string]
(->> (str/split query-string #"&")
(map #(str/split % #"="))
(reduce (fn [acc [k v]]
(update acc (keyword k) #(if % (conj (if (coll? %) % [%]) v) v)))
{})))
(parse-multi-params "color=red&color=blue")
;; => {:color ["red" "blue"]}
处理像?param¶m2=
这样的参数:
(defn parse-params-with-empty [query-string]
(->> (str/split query-string #"&")
(map #(let [[k v] (str/split % #"=" 2)]
[(keyword k) (if (nil? v) "" v)]))
(into {})))
(parse-params-with-empty "param¶m2=")
;; => {:param "", :param2 ""}
确保正确处理URL编码的特殊字符:
(require '[ring.util.codec :as codec])
(def encoded "message=Hello%20World%21")
(codec/form-decode encoded)
;; => {"message" "Hello World!"}
ring.util.codec
,它已经处理了各种边界情况(ns example.params
(:require [ring.util.codec :as codec]
[clojure.string :as str]))
(defn parse-query-string
"解析URL查询字符串,返回Clojure map"
[query-string & {:keys [keywordize?] :or {keywordize? true}}]
(let [params (codec/form-decode query-string)]
(if keywordize?
(->> params
(map (fn [[k v]] [(keyword k) v]))
(into {}))
params)))
;; 使用示例
(parse-query-string "name=John&age=30")
;; => {:name "John", :age "30"}
(parse-query-string "name=John&age=30" :keywordize? false)
;; => {"name" "John", "age" "30"}
这个解决方案提供了灵活的参数解析方式,可以根据需要返回字符串键或关键字键的map。