我试图将所有子目录的列表写入文件,但子目录名称中的 unicode 符号被问号替换。我在 Windows XP 上使用 CLISP 2.49。
这是代码的简短版本:
(let ((*pathname-encoding* (ext:make-encoding :charset 'charset:utf-8
:line-terminator :dos)))
(with-open-file (stream "folders.txt"
:direction :output
:if-exists :overwrite
:if-does-not-exist :create
:external-format (ext:make-encoding :charset 'charset:utf-8
:line-terminator :dos))
(format stream "~A~&" (directory ".\\*\\"))))
最佳答案
你做错了什么
您应该知道 *pathname-encoding*
是 SYMBOL-MACRO ,不是变量。
正如 CLISP 中的注释手册说,
Reminder: You have to use EXT:LETF/EXT:LETF* for SYMBOL-MACROs; LET/LET* will not work!
所以,你需要做的是
(ext:letf ((*pathname-encoding* charset:utf-8)) ...)
(line-terminator
的 *pathname-encoding*
模式无论如何都会被忽略)。
示例
$ touch 'идиотский файл'
$ ls
идиотский файл
$ LANG=C ls
?????????????????? ????????
$ LANG=C clisp -q -norc
> *pathname-encoding*
#<ENCODING CHARSET:ASCII :UNIX>
> *default-file-encoding*
#<ENCODING CHARSET:ASCII :UNIX>
> *terminal-encoding*
#<ENCODING CHARSET:ASCII :UNIX>
> (letf ((*pathname-encoding* charset:utf-8))
(with-open-file (o "foo" :direction :output :external-format charset:utf-8)
(format o "~A~%" (directory "*"))))
NIL
> (quit)
$ cat foo
(/home/sds/tmp/z/идиотский файл /home/sds/tmp/z/foo)
调试您的具体问题
在任何情况下 CLISP 都不会打印或返回 ?
而不是它无法处理的字符 - 它将发出错误信号(尝试省略编码规范之一,您将收到错误 Invalid byte #xD0 in CHARSET:ASCII conversion
- 来自 write
或来自 directory
)。
因此问题出在边界上:
- 操作系统给出 CLISP 问号而不是 unicode(因为它认为 CLISP 无法处理 i18n)
- 或者低级别操作系统层错误地保存了 CLISP 生成的文件
- 或者您用来查看文件的工具无法显示 unicode 字符
(只有最后一个选项似乎合理)。
你可以做的是:
- 首先删除编码规范 - 您是否遇到转换错误?检查默认编码地方(这是符号宏的奇特 Lisp 单词,如
*pathname-encoding*
&c) - 确保
*pathname-encoding*
是utf-8
并尝试类似(coerce (pathname-name (car (directory "*"))) 'list)
- 在上面的示例中我看到(#\CYRILLIC_SMALL_LETTER_I ...)
;你是否像我一样看到unicode字符,或者你看到#\?
? - 尝试
cygwin
(ls
、ls | od
、ls > foo; cat foo | od
)看看它是否可以捕获非 ascii 字符。
关于unicode - 列出其中包含 Unicode 符号的目录名称无法正常工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16185150/