2012-04-08 14 views
11

Clojureの文字列を16進数でエンコードおよびデコードする慣用方法はありますか?パイソンからの例:ClojureはPythonのencode( 'hex')とデコード( 'hex')に相当します

'Clojure'.encode('hex') 
# ⇒ '436c6f6a757265' 
'436c6f6a757265'.decode('hex') 
# ⇒ 'Clojure' 

私の部分にいくつかの努力表示するには:私はあなたのunhexify機能は、それが可能な限り慣用的であると考えてい

(defn hexify [s] 
    (apply str 
    (map #(format "%02x" (int %)) s))) 

(defn unhexify [hex] 
    (apply str 
    (map 
     (fn [[x y]] (char (Integer/parseInt (str x y) 16))) 
     (partition 2 hex)))) 

(hexify "Clojure") 
;; ⇒ "436c6f6a757265" 

(unhexify "436c6f6a757265") 
;; ⇒ "Clojure" 
+0

Javaライブラリを使用しますか? – Marcin

+0

あなたはすでにそれを持っていた – Ankur

+0

@Ankur:明らかにsw1nnの回答として表示されていない - これは私が可能な場合は既存の機能が欲しい理由です。 –

答えて

5

を。しかし、hexifyは簡単な方法で書くことができます。

(defn hexify [s] 
    (format "%x" (new java.math.BigInteger (.getBytes s)))) 
+0

ありがとう、私はそれを処理する組み込みの方法がない場合、あなたの提案を使用します –

+2

これは、最初のビットが1であるバイト配列を "負"としてフォーマットします。 –

+0

私は先行ゼロが削除されることを認識するまでこのメソッドを使用していました。 – mattias

14

あなたの実装(s)はあなたがのバイトをシリアル化する必要が

(defn hexify [s] 
    (apply str 
    (map #(format "%02x" (int %)) s))) 

(defn unhexify [hex] 
    (apply str 
    (map 
     (fn [[x y]] (char (Integer/parseInt (str x y) 16))) 
     (partition 2 hex)))) 

(= "\u2195" (unhexify(hexify "\u2195"))) 
false ; should be true 

はこれを克服するために、非ASCII文字には対応していません文字列は必要な文字エンコーディングを使用します。これは、1文字あたりマルチバイトにすることができます。

これにはいくつかの「問題」があります。

  • すべての数値型は、JVMで署名されています。
  • 符号なしバイトはありません。

慣用的なJavaでは、整数の下位バイトを使用し、それを使用したときはいつでもこのようにマスクします。

int intValue = 0x80; 
    byte byteValue = (byte)(intValue & 0xff); -- use only low byte 

    System.out.println("int:\t" + intValue); 
    System.out.println("byte:\t" + byteValue); 

    -- output: 
    -- int: 128 
    -- byte: -128 

クロージャーは、効果的にこれを行うために(unchecked-byte)を持っています。あなたがこれを行うことができUTF-8を使用して例えば

、:すべての投稿のソリューションは、いくつかの欠点を持っているので

(defn hexify [s] 
    (apply str (map #(format "%02x" %) (.getBytes s "UTF-8")))) 

(defn unhexify [s] 
    (let [bytes (into-array Byte/TYPE 
       (map (fn [[x y]] 
        (unchecked-byte (Integer/parseInt (str x y) 16))) 
         (partition 2 s)))] 
    (String. bytes "UTF-8"))) 

; with the above implementation: 

;=> (hexify "\u2195") 
"e28695" 
;=> (unhexify "e28695") 
"↕" 
;=> (= "\u2195" (unhexify (hexify "\u2195"))) 
true 
+0

パフォーマンスは問題でない限り、これはすべて問題ありません。Pythonの例は、これらのソリューションよりも長い文字列で優れていると思います。パフォーマンスが必要な場合は、さらに多くの作業が必要です。 –

10

は、私は自分自身を共有しています:

(defn hexify "Convert byte sequence to hex string" [coll] 
    (let [hex [\0 \1 \2 \3 \4 \5 \6 \7 \8 \9 \a \b \c \d \e \f]] 
     (letfn [(hexify-byte [b] 
     (let [v (bit-and b 0xFF)] 
      [(hex (bit-shift-right v 4)) (hex (bit-and v 0x0F))]))] 
     (apply str (mapcat hexify-byte coll))))) 

(defn hexify-str [s] 
    (hexify (.getBytes s))) 

(defn unhexify "Convert hex string to byte sequence" [s] 
     (letfn [(unhexify-2 [c1 c2] 
       (unchecked-byte 
        (+ (bit-shift-left (Character/digit c1 16) 4) 
         (Character/digit c2 16))))] 
    (map #(apply unhexify-2 %) (partition 2 s)))) 

(defn unhexify-str [s] 
    (apply str (map char (unhexify s)))) 

長所:

  • 高性能
  • ジェネリックバイトストリーム< - 六角結果の専門ラッパーの先行ゼロの取り扱い
  • と>文字列変換
関連する問題