14

Clojureで文字列を16進数としてエンコードおよびデコードする慣用的な方法はありますか?Pythonの例:

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

私の側でいくつかの努力を示すために:

(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"
4

4 に答える 4

18

投稿されたすべてのソリューションにはいくつかの欠陥があるため、私は自分自身を共有しています:

(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)))) 

長所:

  • ハイパフォーマンス
  • 特殊なラッパーを使用した一般的なバイト ストリーム <--> 文字列変換
  • 16 進結果の先行ゼロの処理
于 2013-03-25T23:58:02.507 に答える
17

あなたの実装はASCII以外の文字では機能しません.

(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 

これを克服するには、必要な文字エンコーディングを使用して文字列のバイトをシリアル化する必要があります。これは、文字ごとにマルチバイトにすることができます。

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

  • JVM ではすべての数値型が符号付きであることに注意してください。
  • unsigned-byte はありません。

慣用的な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

clojure は(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
于 2012-04-10T11:19:43.120 に答える
4

あなたのunhexify機能は可能な限り慣用的だと思います。ただし、hexifyより簡単な方法で書くことができます。

(defn hexify [s]
  (format "%x" (new java.math.BigInteger (.getBytes s))))
于 2012-04-08T17:54:53.007 に答える