Utf 8 通过八位字节解压二进制文件->;字符串->;解包失败:签名的int`#(243 0)`是非法的UTF8

Utf 8 通过八位字节解压二进制文件->;字符串->;解包失败:签名的int`#(243 0)`是非法的UTF8,utf-8,common-lisp,binaryfiles,Utf 8,Common Lisp,Binaryfiles,我正在解析一个混合了字符、浮点、int和short(使用cpan模块作为参考)的二进制文件() 我很幸运地将八位字节序列解析为字符串,这样就可以将它们传递给cl-pack:unpack。这是复杂的,但使用perl模块作为参考进行移植很方便 此策略在将#(243 0)读取为二进制时失败 (setf my-problem (make-array 2 :element-type '(unsigned-byte 8)

我正在解析一个混合了字符、浮点、int和short(使用cpan模块作为参考)的二进制文件()

我很幸运地将八位字节序列解析为字符串,这样就可以将它们传递给
cl-pack:unpack
。这是复杂的,但使用perl模块作为参考进行移植很方便

此策略在将
#(243 0)
读取为二进制时失败

(setf my-problem (make-array 2
                             :element-type '(unsigned-byte 8)
                             :initial-contents #(243 0)))
(babel:octets-to-string my-problem)
非法:从位置0开始的UTF-8字符

并且,当尝试以
char*

八位元序列#(243 0 1 0)无法解码

我希望有一个简单的编码问题我还没有弄明白。试着往相反的方向走(打包
243
并得到八位字节)会得到一个长度为3的向量,而我期望的是2

(babel:string-to-octets (cl-pack:pack "s" 243))
; yields #(195 179 0) expect #(243 0)

完整上下文

;; can read up to position 40. at which we expect 8 signed ints. 
;; 4th int is value "243" but octet cannot be parsed
(setq fid-bin (open "test.nii" :direction :input :element-type 'unsigned-byte))
(file-position fid-bin 40)
(setf seq (make-array (* 2 8) :element-type '(unsigned-byte 8)))
(read-sequence seq fid-bin) 
; seq: #(3 0 0 1 44 1 243 0 1 0 1 0 1 0 1 0)

(babel:octets-to-string seq) ; Illegal :UTF-8 character starting at position 6.
(sb-ext:octets-to-string seq) ; Illegal ....

;; first 3 are as expected
(cl-pack:unpack "s3" (babel:octets-to-string (subseq seq 0 6)))
; 3 256 300

(setf my-problem (subseq seq 6 8)) ; #(243 0)
(babel:octets-to-string my-problem)       ; Illegal :UTF-8 character starting at position 0.

;; checking the reverse direction
;; 243 gets represented as 3 bytes!?
(babel:string-to-octets (cl-pack:pack "s3" 3 256 300))     ; #(3 0 0 1 44 1)
(babel:string-to-octets (cl-pack:pack "s4" 3 256 300 243)) ; #(3 0 0 1 44 1 195 179 0)


(setq fid-str (open "test.nii" :direction :input))
(setf char-seq (make-array (* 2 8) :initial-element nil :element-type 'char*))
(file-position fid-str 40)
(read-sequence char-seq fid-str)
;; :UTF-8 stream decoding error on #<SB-SYS:FD-STREAM ....
;; the octet sequence #(243 0 1 0) cannot be decoded.



问题似乎确实与编码有关:

CL-USER> (cl-pack:pack "s" 243)
"ó\0"
这与以下结果相同:

(babel:octets-to-string my-problem :encoding :iso-8859-1)

问题似乎确实与编码有关:

CL-USER> (cl-pack:pack "s" 243)
"ó\0"
这与以下结果相同:

(babel:octets-to-string my-problem :encoding :iso-8859-1)

问题是,您使用的函数试图将某些八位字节序列视为字符序列(或某些Unicode内容:我认为Unicode中存在字符以外的内容)编码的表示。特别是,在您的例子中,您使用的函数将八位字节序列视为某个字符串的UTF-8编码。嗯,并非所有的八位字节序列都是合法的UTF-8,所以正确地说,函数是在非法的八位字节序列上吐

但那是因为你没有做正确的事情:你要做的是获取一个八位字节序列,并生成一个字符串,其
char-code
s就是这些八位字节。你不想做任何愚蠢的编码大字符在小整数垃圾,因为你永远不会看到任何大字符。您需要类似于这些函数的东西(这两个函数都有点命名错误,因为除非您是这样,否则它们不会对整个八位字节的事情大惊小怪)

现在您可以检查一切是否正常:

> (octetify-string (pack "s" 243))
#(243 0)

>  (unpack "s" (stringify-octets (octetify-string (pack "s" 243))))
243
等等。根据您的示例序列:

> (unpack "s8" (stringify-octets #(3 0 0 1 44 1 243 0 1 0 1 0 1 0 1 0)))
3
256
300
243
1
1
1
1

一个更好的方法是让packing&unpacking函数简单地处理八位字节序列。但我怀疑这是一个失败的事业。一种临时方法是将文件作为文本读取,但使用一种根本不进行翻译的外部格式,这种方法虽然可怕,但不如将八位字节序列转换为字符那么可怕。如何做到这一点取决于实现(但基于拉丁语-1的东西将是一个良好的开端)。

问题在于,您使用的函数试图将某些八位字节序列视为字符序列(或某些Unicode内容:我认为Unicode中存在字符以外的其他内容)编码的表示。特别是,在您的例子中,您使用的函数将八位字节序列视为某个字符串的UTF-8编码。嗯,并非所有的八位字节序列都是合法的UTF-8,所以正确地说,函数是在非法的八位字节序列上吐

但那是因为你没有做正确的事情:你要做的是获取一个八位字节序列,并生成一个字符串,其
char-code
s就是这些八位字节。你不想做任何愚蠢的编码大字符在小整数垃圾,因为你永远不会看到任何大字符。您需要类似于这些函数的东西(这两个函数都有点命名错误,因为除非您是这样,否则它们不会对整个八位字节的事情大惊小怪)

现在您可以检查一切是否正常:

> (octetify-string (pack "s" 243))
#(243 0)

>  (unpack "s" (stringify-octets (octetify-string (pack "s" 243))))
243
等等。根据您的示例序列:

> (unpack "s8" (stringify-octets #(3 0 0 1 44 1 243 0 1 0 1 0 1 0 1 0)))
3
256
300
243
1
1
1
1
一个更好的方法是让packing&unpacking函数简单地处理八位字节序列。但我怀疑这是一个失败的事业。一种临时方法是将文件作为文本读取,但使用一种根本不进行翻译的外部格式,这种方法虽然可怕,但不如将八位字节序列转换为字符那么可怕。如何做到这一点取决于实现(但基于拉丁语-1的东西将是一个良好的开端)