【问题标题】:Convert a UTF-32 encoded string (C style) in a UTF-16 (JSON style) encoded one in Java/Clojure将 UTF-32 编码的字符串(C 风格)转换为 UTF-16(JSON 风格)编码的 Java/Clojure
【发布时间】:2015-03-17 14:23:50
【问题描述】:

我从一个服务接收到一个字符串,该字符串显然使用 UTF-32 编码对其 unicode 字符进行编码,例如:\U0001B000(C 风格的 unicode 编码)。但是,为了在 JSON 中序列化这些信息,我必须将其编码为 UTF-16,例如:\uD82C\uDC00

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

【问题讨论】:

    标签: java json unicode encoding clojure


    【解决方案1】:

    您可以使用以下方式从服务中读取接收到的字节:

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

    【讨论】:

    • 它并没有真正按照我的意图工作。我尝试了(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
    • 你确定你的 unicode.input 是 UTF-32 编码的吗? (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 的输出。
    • @Neoasimov 请注意,在调用spit 时,您写的是:encode 而不是:enconding
    • @Symfrog,@juan-facorro:感谢您的投入!是的,这会起作用,但也许我对我的问题不清楚。我正在寻找的是使用用 C 编写的 UTF-32,例如表示 \U0001B000,然后用 JSON 写回,例如表示 UTF-16:\uD82C\uDC00。这个slurp 电话真的应该这样做吗?如果是这样,我还是有问题。
    • @Neoasimov 您能否提供通过 xxd 运行的资源/unicode.input 的最小样本,即xxd resources/unicode.input
    【解决方案2】:

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

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

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

    【讨论】:

      猜你喜欢
      • 2012-07-23
      • 2019-03-13
      • 2014-01-18
      • 2012-06-30
      • 1970-01-01
      • 1970-01-01
      • 2015-09-06
      • 1970-01-01
      • 2017-02-01
      相关资源
      最近更新 更多