我从一个服务中接收到了一个字符串,该服务显然使用UTF-32编码来编码其Unicode字符,如:\U0001B000
(C样式的unicode编码)。但是,为了将此信息序列化为JSON,我必须将其编码为UTF-16,如:\uD82C\uDC00
。
然而,我不知道如何在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."
免责声明:我没有考虑过边缘(或者除了提供的之外的其他)情况。但是我相信您可以将这个作为进一步探索的基础。
(spit "resources/unicode.output" (slurp "resources/unicode.input" :encoding "UTF-32") :encode "UTF-16")
,但它没有产生我在问题中提到的JSON / UTF-16编码。还请注意,我放入unicode.input
文件中的字符串是\U0001B000
,而我用slurp
获取的是3个字节:0xFFFD 0xFFFD 0xFFFD
。 - Neoasimov(spit "out.txt" (slurp "in.txt" :encoding "UTF-32") :encoding "UTF-16")
,其中in.txt为0000000: 0000 feff 0001 b000 0000 000a
,out.txt为0000000: feff d82c dc00 000a
,这是运行xxd
后的输出结果。 - Symfrogspit
函数时,你写成了:encode
而不是:encoding
。 - juan.facorroxxd resources/unicode.input
。 - Symfrog