Clojure通过组成部分构建URL

14

在Python中,我会执行以下操作:

>>> q = urllib.urlencode({"q": "clojure url"})
>>> q
'q=clojure+url'

>>> url = "http://stackoverflow.com/search?" + q
>>> url
'http://stackoverflow.com/search?q=clojure+url'

我如何在Clojure中完成上述为我完成的全部编码?换句话说,我该如何执行类似于以下操作的任务:

=> (build-url "http://stackoverflow.com/search" {"q" "clojure url"})
"http://stackoverflow.com/search?q=clojure+url"
6个回答

19

Ring 的 ring.util.codec 命名空间中有一个 url-encode 函数:

(ring.util.codec/url-encode "clojure url")
; => "clojure+url"

我不确定是否有一个预设的函数可以将一个映射转换成查询字符串,但也许这个方法可以完成任务:

(use '[ring.util.codec :only [url-encode]])

(defn make-query-string [m]
  (->> (for [[k v] m]
         (str (url-encode k) "=" (url-encode v)))
       (interpose "&")
       (apply str)))
一个例子:
user> (make-query-string {"q" "clojure url" "foo" "bar"})
"q=clojure+url&foo=bar"

现在只需要将结果连接到一个URL的末尾:

(defn build-url [url-base query-map]
  (str url-base "?" (make-query-string query-map)))

似乎可以正常工作:

user> (build-url "http://stackoverflow.com/search" {"q" "clojure url"})
"http://stackoverflow.com/search?q=clojure+url"

更新:

也许修改版本会为Clojure提供更友好的体验。同时,通过一个可选的参数进行编码处理,采用utf-8作为默认值。

(defn make-query-string [m & [encoding]]
  (let [s #(if (instance? clojure.lang.Named %) (name %) %)
        enc (or encoding "UTF-8")]
    (->> (for [[k v] m]
           (str (url-encode (s k) enc)
                "="
                (url-encode (str v) enc)))
         (interpose "&")
         (apply str))))

(defn build-url [url-base query-map & [encoding]]
  (str url-base "?" (make-query-string query-map encoding)))

现在我们可以这样做

user> (build-url "http://example.com/q" {:foo 1})
"http://example.com/q?foo=1"

啊,差点忘了:ring.util.codec 也接受一个可选的编码参数,默认为 UTF-8 - Michał Marczyk

15

这是一种方法:

user=> (import [java.net URLEncoder])                                                      
java.net.URLEncoder
user=> (str "http://stackoverflow.com/search?q=" (URLEncoder/encode "clojure url" "UTF-8"))
"http://stackoverflow.com/search?q=clojure+url"

我知道这与你的Python代码片段不完全相同。请参阅Clojure邮件列表中的以下帖子以获取更完整的答案:

http://www.mail-archive.com/clojure@googlegroups.com/msg29338.html

那里的代码将允许您执行以下操作:

user=> (encode-params {"q" "clojure url"})
"q=clojure+url"

注意到这个编辑,我猜我不应该费心写那么多... 哦,算了。第一个完整答案加1分。我仍然喜欢我的Named处理版本,所以我把它留在这里。 :-) - Michał Marczyk

11

这是使用clj-http的准确REPL等效于您的Python会话。

user=> (require ['clj-http.client :as 'client])
nil
user=> (str "http://stackoverflow.com/search?"
user=*      (client/generate-query-string {"q" "clojure url"}))
"http://stackoverflow.com/search?q=clojure+url"

但是clj-http使它变得更容易了:

user=> (client/get "http://stackoverflow.com/search?"
user=*             {:query-params {"q" "clojure url"}})
... <a lot of output, omitted to protect the innocent>...

假设你想执行一个GET请求。


2

clj-apache-http非常有用。使用它,您可以执行以下操作:

user=> (require ['com.twinql.clojure.http :as 'http])
nil
user=> (def q (http/encode-query {"q" "clojure url"}))
#'user/q
user=> (def url (str "http://stackoverflow.com/search?" q))
#'user/url
user=> url
"http://stackoverflow.com/search?q=clojure+url"

1

-2
一个使用字符串的简单解决方案:
(def q (str "clojure+url"))
(def url (str "http://stackoverflow.com/search?" q))

你正在输入 +,所以实际上并没有让Clojure为你编码字符串。 - Stéphane Bruckert

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接