在打开文件之前检测编码

时间:2016-06-03 06:42:52

标签: character-encoding common-lisp file-handling sbcl

我收到了一个包含未知字符编码的文件。正在运行file -bi test.trace会返回text/plain; charset=us-ascii但使用

(with-open-file (stream "/home/*/test.trace" :external-format :us-ascii)
 (code-to-work-with-file))

给了我一个例外:

:ASCII stream decoding error on
#<SB-SYS:FD-STREAM for "file /home/*/test.trace"   {10208D2723}>:

  the octet sequence #(194) cannot be decoded.    [Condition of type SB-INT:STREAM-DECODING-ERROR]

如何在打开文件之前检测文件的编码?

我可以使用emacslessnano打开文件,因为它似乎是对编码的错误检测或file的差异并且sbcl认为编码应该是这样的。

我目前通过强制每个文件使用vim +set nobomb | set fenc=utf8| x file-path进行utf8编码来避免此问题。但即便在此file仍然认为它是us-ascii编码之后。另外,这不是一个有效的永久解决方案,而是一个让它工作的肮脏黑客。

1 个答案:

答案 0 :(得分:1)

正如here中的prorgammers stackexchange指出的那样,

  

文件通常用文件头指示它们的编码。有   这里有很多例子。然而,即使阅读标题,你也永远不会   确定文件的编码实际使用的是什么。

我在我的系统中查找了跟踪文件并找到了这个,但这没有任何有趣的东西

2016-06-22 13:10:07☆| ruby​​-2.2.3@laguna | Antonios-MacBook-Pro在〜/ learn / lisp / stackoverflow / scripts中 ○→文件-I resources / hello.trace resources / hello.trace:text / plain;字符集= US-ASCII

2016-06-22 13:11:50☆| ruby​​-2.2.3@laguna | Antonios-MacBook-Pro在〜/ learn / lisp / stackoverflow / scripts中 ○→cat资源/ hello.trace 调用println! {&#34;你好,世界!&#34; } 打印! {concat! (&#34;你好,世界!&#34;,&#34; \ n&#34;)}

所以使用这段代码,我可以读到它:

CL-USER> (with-open-file (in "/Users/toni/learn/lisp/stackoverflow/scripts/resources/hello.trace" :external-format :us-ascii)
           (when in
    (loop for line = (read-line in nil)
         while line do (format t "~a~%" line))))
println! { "Hello, World!" }
print! { concat ! ( "Hello, World!" , "\n" ) }
NIL

甚至用中文或其他任何东西:

rare output

我们可以像这样阅读ascci字符

CL-USER> (format nil "~{~C~}" (mapcar #'code-char '(194)))
"Â"

或任何其他奇怪的角色,所以似乎可以是带有重音的字符我将其添加到文件中:

 println! { "Hello, World!" }
print! { concat ! ( "Hello, World!" , "\n" ) }
Â
patatopita

我得到同样的错误:

上的ASCII流解码错误

for&#34; file /Users/toni/learn/lisp/stackoverflow/scripts/resources/hello.trace"   {1003994043}&GT;:

八位字节序列#(195)无法解码。    [SB-INT型的条件:STREAM-DECODING-ERROR]

所以此时你可以使用续约和重新启动,更改字符,有一个选项,我不是这类代码的专家,但可能会重新启动

Restarts:
 0: [ATTEMPT-RESYNC] Attempt to resync the stream at a character boundary and continue.
 1: [FORCE-END-OF-FILE] Force an end of file.
 2: [INPUT-REPLACEMENT] Use string as replacement input, attempt to resync at a character boundary and continue.
 3: [*ABORT] Return to SLIME's top level.
 4: [ABORT] abort thread (#<THREAD "repl-thread" RUNNING {10050E0003}>)

输入替换,如果没有像拉丁语1或ISO那样尝试欧洲......

CL-USER> (with-open-file (in "/Users/toni/learn/lisp/stackoverflow/scripts/resources/hello.trace" :external-format :latin-1)
           (when in
    (loop for line = (read-line in nil)
         while line do (format t "~a~%" line))))
println! { "Hello, World!" }
print! { concat ! ( "Hello, World!" , "\n" ) }
¬
patatopita
NIL

它应该有效,祝你好运

所以让我们阅读欧洲字符集