将 UTF-32 编码的字符串(C 样式)转换为 Java/Clojure 中编码的 UTF-16(JSON 样式)字符



我从一个服务接收一个字符串,该服务显然使用 UTF-32 编码对其 unicode 字符进行编码,例如:U0001B000(C 样式 unicode 编码)。但是,为了在 JSON 中序列化此信息,我必须用 UTF-16 对其进行编码,例如:uD82CuDC00 .

但是,我不知道如何在Java/Clojure中读取这样的编码字符串,以及如何使用其他编码格式生成输出。

您可以使用以下命令从服务读取收到的字节:

(slurp received-bytes :encoding "UTF-32")

并使用以下命令编写字符串:

(spit destination string-to-encode :encoding "UTF-16")

如果您的意思是您有一个表示编码字符二进制的字符串,则可以使用以下方法对其进行转换:

(defn utf32->str [utf32-str]
  (let [buf (java.nio.ByteBuffer/allocate 4)]
    (.putInt buf (Integer/parseInt (subs  utf32-str 2) 16))
    (String. (.array buf) "UTF-32")))
(utf32->str "\U0001B000" )

然后使用以下方法将其转换为 UTF-16:

(defn str->utf16 [s]
  (let [byte->str #(format "%02x" %)]
    (apply str
           (drop 1 (map #(str "\U" (byte->str (first %) ) (byte->str (second %) ))
                        (partition 2 (.getBytes s "UTF-16")))))))

下面是一个运行示例:

(str->utf16 (utf32->str "\U0001B000"))
;=> "\Ud82c\Udc00"

一旦你有了要替换的字符串,下面的函数就可以了:

(defn escape-utf16
  [[_ _ a b c d]]
  (format "\u%02X%02X\u%02X%02X" a b c d))
(defn replace-utf32
  [^String s]
  (let [n (Integer/parseInt (subs s 2) 16)]
    (-> (->> (map #(bit-shift-right n %) [24 16 8 0])
             (map #(bit-and % 0xFF))
             (byte-array))
        (String. "UTF-32")
        (.getBytes "UTF-16")
        (escape-utf16))))
(replace-utf32 "\U0001B000")
;; => "\uD82C\uDC00"

并且,对于有针对性的替换,请使用正则表达式:

(require '[clojure.string :as string])
(string/replace
   "this is a text \U0001B000."
   #"\U[0-9A-F]{8}"
   replace-utf32)
;; => "this is a text \uD82C\uDC00."

免责声明:我没有考虑过边缘(或提供的任何其他情况)情况。但我相信你可以以此为基础进行进一步探索。

最新更新