1

我有一个 clj 文件:

;; stringparity.clj ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(ns stringparity)

    (defn get-java-string [input]
      (.getBytes input "UTF-8"))

还有一个 cljs 文件:

;;; stringparity.cljs ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(ns stringparity
  (:import goog.crypt))    

    (defn get-js-string [input]
      (goog.crypt.stringToUtf8ByteArray input))

以下代码不可执行,get-js-string只适用于javascript,get-java-string适用于java;我只是假装你可以在同一台机器上运行它们来说明出了什么问题。这两个函数在使用“简单”字符串时都可以正常工作,但在使用“复杂”字符串(如"". 我希望能够对 clojure 或 clojurescript 上的任何字符串进行哈希处理,并使它们的哈希值相同。为此,我需要能够将 javascript 或 java 字符串转换为其等效的字节数组。看来我在 clojure 和 clojurescript 方面都使用 UTF-8,但它们不会生成相同的字节数组(它们甚至不是相同的长度)。如何为 clojure 和 clojurescript 中的任何两个等效字符串生成完全相同的字节数组。

(= (seq (get-js-string "hello"))  [104, 101, 108, 108, 111]
   (seq (get-java-string "hello") [104, 101, 108, 108, 111]))


(= (seq (get-js-string ""))
   ;; when in cljs, get-js-string evaluates to the following
   [237 160 180 237 188 134]
   (seq (get-java-string ""))
   ;; when in clj, get-java-string evaluates to the following
   [-16 -99 -116 -122])
4

2 回答 2

4

goog.crypt.stringToUtf8ByteArray无法处理在 Javascript 字符串中表示为“代理对”的字符(例如您的 "" 示例)并产生不正确的结果。

如果您不需要 UTF-8,但只需要一个字节值序列来生成哈希,则一种替代方法是在两种情况下将字符编码为 UTF-16 字节序列:

cljs:

(defn to-byte [n] (if (>= n 128) (- n 256) n))

(defn get-js-string [input]
  (map to-byte
    (mapcat
      #(let [u (.charCodeAt input %)]
         [(-> (bit-and u 0xFF00) (bit-shift-right 8)) (bit-and u 0xFF)]) 
      (range (.-length input)))))

clj:

(defn get-java-string [input]
  (.getBytes input "UTF-16BE"))

这应该(-40 52 -33 6)在这两种情况下为您提供示例字符串的序列。

于 2013-10-15T16:00:13.857 回答
4

The javascript implementation doesn't properly handle characters with codepoints above 65535.

于 2013-10-14T19:43:50.000 回答