2011-07-06 5 views
19

私はこの要求して を取る機能(defn request->map [request] ...)を書くの慣用的な方法は、ここでマップ{:size 3, :mean 1, :sd 3, :type pdf, :distr normal}ClojureでURLパラメータを解析するには?

を返し何要求"size=3&mean=1&sd=3&type=pdf&distr=normal"を持っている場合(clojure.walkとclojure.stringを使用して)私の試みです:

(defn request-to-map 
    [request] 
    (keywordize-keys 
     (apply hash-map 
      (split request #"(&|=)")))) 

私は他人がこの問題をどのように解決するかに興味があります。

答えて

10

あなたはJavaライブラリの数で簡単にこれを行うことができます。 URI仕様を慎重に読んで、私が辺のケース(例えば、クエリで異なる値で2回出現するparams)を見落としていないことを確認しない限り、私自身のパーサをロールしようとするのは躊躇します。これはjetty-utilを使用しています:

form-decodekeywordize-keysを使用して
(import '[org.eclipse.jetty.util UrlEncoded MultiMap]) 

(defn parse-query-string [query] 
    (let [params (MultiMap.)] 
    (UrlEncoded/decodeTo query params "UTF-8") 
    (into {} params))) 

user> (parse-query-string "size=3&mean=1&sd=3&type=pdf&distr=normal") 
{"sd" "3", "mean" "1", "distr" "normal", "type" "pdf", "size" "3"} 
+0

UrlEncodedクラスが変更され、上記のコードがJetty 9.2.10で機能しないことに注意してください。 この作品: (defn-構文解析クエリ文字列は、[クエリ] ( - >>クエリ URLエンコード()} {に (clojure.algo.generic。functor/fmap first))) – skrii

3

あなたはうまく見えます。私は正規表現を酷使する傾向があるので、私は

(defn request-to-keywords [req] 
    (into {} (for [[_ k v] (re-seq #"([^&=]+)=([^&]+)" req)] 
    [(keyword k) v]))) 

(request-to-keywords "size=1&test=3NA=G") 

{:size "1", :test "3NA=G"} 

編集として、それを解決しているだろう。しかし離れclojure.walkから滞在してみてください。私はそれが正式に推奨されていないとは思わないが、あまりよく管理されていない。 (私はそれをたくさん使っていますが、あまりにも悪くはありません)。

+0

は本当に、問題を解決する方法として、この総正規表現を推薦するが、いくつか... for'に 'のような面白いイディオムと'再配列にあなたを公開しようとしていません'。 – amalloy

+0

あなたのコードが何をしているのか私の頭を掴みようとしていますが、私はそれを次のようにしようとしています:size "1" using Integer/parseIntコードはまだ – ChrisR

+0

また、URLDecode、いいえ? –

16

HTTPリクエストクエリのパラメータを解析すると仮定して、ringを使用しないのはなぜですか? ring.middleware.paramsにはあなたが望むものが含まれています。

パラメータ抽出のための機能は、このように書きます:

(defn- parse-params 
    "Parse parameters from a string into a map." 
    [^String param-string encoding] 
    (reduce 
    (fn [param-map encoded-param] 
     (if-let [[_ key val] (re-matches #"([^=]+)=(.*)" encoded-param)] 
     (assoc-param param-map 
      (codec/url-decode key encoding) 
      (codec/url-decode (or val "") encoding)) 
     param-map)) 
    {} 
    (string/split param-string #"&"))) 
13

(use 'ring.util.codec) 
(use 'clojure.walk) 

(keywordize-keys (form-decode "hello=world&foo=bar")) 

{:foo "bar", :hello "world"} 
+0

リング1.2を使用している場合の最も単純な答え –

3

もClojureのとclojurescriptの両方のために、このライブラリを使用することができます:私を構築する際にhttps://github.com/cemerick/url

user=> (-> "a=1&b=2&c=3" cemerick.url/query->map clojure.walk/keywordize-keys) 
{:a "1", :b "2", :c "3"} 
0

私はこの質問に出くわしましたパラメータを内部的に渡すのであれば、答えは少し違うかもしれません。

ルーティングを処理するために事務の使用:ルートの一致が発見された場合、クエリのparams:https://github.com/gf3/secretary

パラメータが自動的にマップに抽出されます。ドキュメントに与えられた例:

(defroute "https://stackoverflow.com/users/:id" [id query-params] 
    (js/console.log (str "User: " id)) 
    (js/console.log (pr-str query-params))) 

(defroute #"https://stackoverflow.com/users/(\d+)" [id {:keys [query-params]}] 
    (js/console.log (str "User: " id)) 
    (js/console.log (pr-str query-params))) 

;; In both instances... 
(secretary/dispach! "https://stackoverflow.com/users/10?action=delete") 
;; ... will log 
;; User: 10 
;; "{:action \"delete\"}" 
関連する問題