【发布时间】:2013-11-08 15:55:27
【问题描述】:
我今天尝试编写一个 elisp 函数,一切正常,除了当函数返回 nil 时不断抛出错误。这是函数:(请原谅格式,我还不确定如何缩进。)
(defun byte-is-readable (byte)
"Determine whether BYTE is readable or not.
Returns t or nil."
(if (and (<= byte 126) (>= byte 32)) t nil))
;; Read the 100 bytes of a file
;; If 10 in a row are not 'readable', it is safe to assume the file is a binary
(defun is-file-binary (file)
"Determine whether FILE is a binary file.
Returns t or nil."
(let* ((i 1)
(c 0)
(size (nth 7 (file-attributes file)))
(lim (if (< size 100) size 100)))
(while (< i lim)
(let ((char (with-temp-buffer
(insert-file-contents file)
(buffer-substring i (+ i 1)))))
(if (not (byte-is-readable (aref char 0)))
(setq c (+ c 1))
(setq c 0))
(if (= c 10) (return t)))
(setq i (+ i 1))))
nil)
这样调用它:(message "%s" (if (is-file-binary "/path/to/some/file") "true" "false") 在返回 true 时工作文件,但在返回 nil 时抛出“if: No catch for tag: --cl-block-nil--, t”。我猜这是因为 nil 没有被正确评估或其他原因。
我该如何解决?
【问题讨论】:
-
您似乎正在创建一个新的临时缓冲区,并在每次通过 WHILE 循环时将 FILE 的内容加载到其中。这似乎效率低下。为什么不将 WITH-TEMP-BUFFER 包裹在 WHILE 周围?
(with-temp-buffer (insert-file-contents file) (while (< i lim) (let ((char (buffer-substring i (1+ i)))) ... ))这样,您只需加载 FILE 的内容一次,而不是最多 100 次——对于小文件,它不会有什么不同,但是,因为您将整个文件加载到缓冲区中,对于大文件,它很可能。 (额外的功劳:只加载你需要的字节。) -
另外,你根本不需要打破 WHILE 循环;您可以简单地让它自己耗尽,之后您将获得 C 中“可读”字节的计数。然后,用
(< c 10)替换 LET 表单末尾的裸露 NIL,如果存在,该函数将返回 T少于十个“可读”字节,如果有十个或更多,则为 NIL。 -
你也可以去掉 LIM 绑定,因为你只在一个地方使用它;只需从 LET 绑定表单中删除该绑定,然后将
(if (< size 100) size 100)表单用于 WHILE 测试中 -
@AaronMiller:考虑改写您的 cmets 作为答案。例如,它们提供的答案与 wvxvw 的答案一样多。
-
你不需要这一切:
(if (and (<= byte 126) (>= byte 32)) t nil)),除非你真的关心t作为非nil值。这足够了:(and (<= byte 126) (>= byte 32)).