unicode - 仅在提示符下执行时才出现 sbcl 编码错误?

标签 unicode utf-8 lisp common-lisp sbcl

我有一段代码,如果从 emacs 中的 slime 提示符执行,它会毫无错误地运行。如果我从提示符下启动 sbcl,我得到错误:

* (ei:proc-file "BRAvESP000.log" "lixo")

debugger invoked on a SB-INT:STREAM-ENCODING-ERROR:
  :UTF-8 stream encoding error on
  #<SB-SYS:FD-STREAM for "file /Users/arademaker/work/IBM/scolapp/lixo"
    {10049E8FF3}>:

    the character with code 55357 cannot be encoded.

Type HELP for debugger help, or (SB-EXT:EXIT) to exit from SBCL.

restarts (invokable by number or by possibly-abbreviated name):
  0: [OUTPUT-NOTHING    ] Skip output of this character.
  1: [OUTPUT-REPLACEMENT] Output replacement string.
  2: [ABORT             ] Exit debugger, returning to top level.

(SB-IMPL::STREAM-ENCODING-ERROR-AND-HANDLE #<SB-SYS:FD-STREAM for "file /Users/arademaker/work/IBM/scolapp/lixo" {10049E8FF3}> 55357)
0]

奇怪的是,在这两种情况下,我都使用相同的 sbcl 1.1.8 和同一台机器,Mac OS 10.8.4。任何想法?

代码:

(defun proc-file (filein fileout &key (fn-convert #'identity))
  (with-open-file (fout fileout
                   :direction :output
                   :if-exists :supersede
                   :external-format :utf8)
    (with-open-file (fin filein :external-format :utf8)
      (loop for line = (read-line fin nil)
        while line
        do 
        (handler-case
        (let* ((line (ppcre:regex-replace "^.*{jsonTweet=" line "{\"jsonTweet\":"))
               (data (gethash "jsonTweet" (yason:parse line))))
          (yason:encode (funcall fn-convert (yason:parse data)) fout)
          (format fout "~%"))
          (end-of-file ()
        (format *standard-output* "Error[~a]: ~a~%" filein line)))))))

最佳答案

这几乎可以肯定是 yason 中的错误。 JSON 要求如果转义非 BMP 字符,则通过代理项对转义。这是一个 U+10000 的简单示例(可以选择在 json 中转义为“\ud800\udc00”;我使用 babel,因为 babel 的转换不太严格):

(map 'list #'char-code (yason:parse "\"\\ud800\\udc00\"")) 
  => (55296 56320)

unicode 代码点 55296(十进制)是代理对的开始,除非作为 UTF-16 中的代理对,否则不应出现。幸运的是,它可以通过使用 babel 将字符串编码为 UTF-16 并再次返回来轻松解决:

(babel:octets-to-string (babel:string-to-octets (yason:parse "\"\\ud800\\udc00\"") :encoding :utf-16le) :encoding :utf-16le)
  => "𐀀"

您应该可以通过更改此行来解决此问题:

(yason:encode (funcall fn-convert (yason:parse data)) fout)

使用中间字符串,将其转换为 UTF-16 并返回。

(write-sequence
 (babel:octets-to-string
  (babel:string-to-octets
   (with-output-to-string (outs)
    (yason:encode (funcall fn-convert (yason:parse data)) outs))
   :encoding :utf-16le)
  :encoding :utf-16le)
 fout)

我提交了一个已被接受的补丁以在 yason 中修复此问题:

https://github.com/hanshuebner/yason/commit/4a9bdaae652b7ceea79984e0349a992a5458a0dc

关于unicode - 仅在提示符下执行时才出现 sbcl 编码错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17665322/

相关文章:

java - 如何制作 Java.awt.Robot 类型的 unicode 字符? (可能吗?)

javascript - 如何在ajax请求中转义括号?

java - 使用 Unicode 作为 Java 变量?

macos - MATLAB:如何显示从文件中读取的 UTF-8 编码文本?

recursion - Lisp 中的递归加法

iphone - 如何在 Objective-C 中的 PDF 中添加欧元货币符号

python - 使用编码的 unicode 字符串时字符串格式错误

python - 这个字符串的编码是什么?

lisp - CLISP:变量 <x> 从函数返回时没有值

recursion - 如何在 Lisp 中制作深度反转函数