Function Emacs Lisp:“您必须遵守《全国人大常委会关于维护互联网安全的决定》及中华人民共和国其他有关法律法规。”;如果:标签--cl block nil--,t";当返回零时
今天我试着编写一个elisp函数,除了函数返回nil时不断抛出的一个错误外,其他都很好。函数如下:(请原谅格式化,我还不确定如何缩进。)Function Emacs Lisp:“您必须遵守《全国人大常委会关于维护互联网安全的决定》及中华人民共和国其他有关法律法规。”;如果:标签--cl block nil--,t";当返回零时,function,emacs,elisp,Function,Emacs,Elisp,今天我试着编写一个elisp函数,除了函数返回nil时不断抛出的一个错误外,其他都很好。函数如下:(请原谅格式化,我还不确定如何缩进。) (defun字节是可读的(字节) “确定字节是否可读。 返回t或nil。“ (如果(和(=字节32))t nil) ;; 读取文件的100字节 ;; 如果一行中有10个文件不“可读”,则可以安全地假定该文件是二进制文件 (defun是文件二进制(file) “确定文件是否为二进制文件。 返回t或nil。“ (让*((i)1) (c 0) (大小(第n个7(文件
(defun字节是可读的(字节)
“确定字节是否可读。
返回t或nil。“
(如果(和(=字节32))t nil)
;; 读取文件的100字节
;; 如果一行中有10个文件不“可读”,则可以安全地假定该文件是二进制文件
(defun是文件二进制(file)
“确定文件是否为二进制文件。
返回t或nil。“
(让*((i)1)
(c 0)
(大小(第n个7(文件属性文件)))
(lim(如果(<尺寸100)尺寸100)))
(while(
像这样调用它:(消息“%s”(if(is file binary)/path/to/some/file)“true”或“false”)
在返回true时对file起作用,但在返回nil时抛出“if:No catch for tag:--cl block nil--,t”。我猜这是因为nil的计算不正确或其他原因
如何修复它?错误源于您在代码中使用了
return
。这是一个宏,仅在其他一些cl
宏(例如loop
)的上下文中进行有意义的完全扩展
(defun byte-readable-p (byte)
"Determine whether BYTE is readable or not.
Returns t or nil."
(cl-case byte
((?\n ?\r ?\t) t)
(otherwise (and (<= byte 126) (>= byte 32)))))
(defun file-binary-p (file)
"Determine whether FILE is a binary file.
Returns t or nil."
(with-temp-buffer
(insert-file-contents file)
(cl-loop for c across
(buffer-substring-no-properties
1 (min 100 (buffer-size)))
thereis (not (byte-readable-p c)))))
(file-binary-p (expand-file-name "~/.emacs"))
nil
(file-binary-p (expand-file-name "~/.emacs.d/elpa/w3m-20131021.2047/w3m.elc"))
t
我鼓励您使用循环
而不是while
,因为它允许隐藏无趣的实现细节,例如计数器、抛出
-捕获
机制等。但是,如果出于任何原因,您想使用while
循环,则打破while
循环的方法是:
(catch 'label (while <condition> ... (throw 'label <result>)))
或者,更简短的版本,使用高阶函数:
(defun file-binary-p (file)
"Determine whether FILE is a binary file.
Returns t or nil."
(with-temp-buffer
(insert-file-contents file)
(cl-find-if-not 'byte-readable-p
(buffer-substring-no-properties
1 (min 100 (buffer-size))))))
请注意,在传统的Lisp代码中,函数返回布尔值(通常称为“谓词”)使用以下方案命名:
p
或--p
而不是is-
在每次通过WHILE循环时,您似乎都在创建一个新的临时缓冲区,并将文件内容加载到其中。这似乎效率不高。为什么不在WHILE周围使用-temp-buffer?(使用临时缓冲区(插入文件内容文件)(虽然(
通过这种方式,您只需加载文件内容一次,而不是最多加载100次——对于小文件,这不会有什么区别,但是,由于您将整个文件加载到缓冲区中,对于大文件,这很有可能。(额外积分:只加载所需的字节。)此外,您根本不需要中断WHILE循环;您可以简单地让它自己耗尽,然后在C中计算“可读”字节数。然后,用(
)替换let表单末尾的空零,如果少于10,函数将返回t“可读”字节,如果有10个或更多字节,则为零。您也可以取消LIM绑定,因为您只在一个位置使用它;只需从LET绑定表单中删除该绑定,然后使用(if(表单为“在您的测试中调用”的第二个参数。“ArnnMulle:考虑将您的注释作为回答。例如,它们提供了与WVXVW的答案一样多的答案。您不需要所有这些:<代码>(如果(和(=字节32))nIL))
,除非你真的关心t
作为非nil
值。这就足够了:(和(=字节32))
。工作起来很有魅力,谢谢。我对函数的功能有点困惑。它们是否检查所有100个字节都是“可读的”?因为如果文件中有“可读”字符,那么这将失败(elf文件以字母elf开头,ZIP以PK开头),但它没有。@ronmrdechai函数搜索文件开头100个或更少字节内的第一个字节(实际上是字符),该字节超出了byte-readable-p
设置的范围。
(defun file-binary-p (file)
"Determine whether FILE is a binary file.
Returns t or nil."
(with-temp-buffer
(insert-file-contents file)
(cl-find-if-not 'byte-readable-p
(buffer-substring-no-properties
1 (min 100 (buffer-size))))))