当达到eof时,读取线如何在Lisp中工作?

时间:2017-02-08 01:11:31

标签: file-io lisp common-lisp

上下文: 我有一个名为fr.txt的文本文件,其中包含3列文字:

65  A   #\A
97  a   #\a
192     À   #\latin_capital_letter_a_with_grave
224     à   #\latin_small_letter_a_with_grave
etc...

我想创建一个函数来读取第一个(也最终是第三个)列,并将其写入另一个名为alphabet_code.txt的文本文件中。

到目前为止,我有这个功能:

(defun alphabets()
   (setq source (open "fr.txt" :direction :input :if-does-not-exist :error))
   (setq code (open "alphabet_code.txt" :direction :output :if-does-not-exist :create :if-exists :supersede))
   (loop
      (setq ligne (read-line source nil nil))
      (cond
         ((equal ligne nil) (return))
         (t (print (read-from-string ligne) code))
      )
   )
   (close code)
   (close source)
)

我的问题:

  1. 我真的不明白读取线功能的参数如何。我读过this doc,但它对我来说仍然很模糊。如果有人会有非常简单的例子,那会有所帮助。

  2. 使用当前代码,即使我将*** - read: input stream #<input string-input-stream> has reached its end中的nil nil更改为其他值,我也会收到此错误:(read-line source nil nil)

  3. 谢谢你的时间!

1 个答案:

答案 0 :(得分:7)

您的问题

read-line可选参数

read-line接受3个可选参数:

  1. eof-error-p:如何处理EOF(默认:错误)
  2. eof-value:当您看到EOF
  3. 时,返回什么而不是错误
  4. recursive-p:你是用print-object方法调用的吗(暂时忘掉这个)
  5. ,例如,当stream处于EOF时,

    • (read-line stream)会发出end-of-file错误信号
    • (read-line stream nil)将返回nil
    • (read-line stream nil 42)将返回42

    请注意,(read-line stream nil)(read-line stream nil nil)相同,但人们通常仍会明确传递第二个可选参数。 eof-value nil的{​​{1}}适用于read-line,因为nil不是字符串而read-line只返回字符串。

    另请注意,在read的情况下,第二个可选参数传统上是stream本身:(read stream nil stream)。这很方便。

    错误

    您收到来自read-from-string而非read-line的错误,因为显然您的文件中有一个空行。

    我知道,因为错误提到string-input-stream,而不是file-stream

    您的代码

    您的代码在功能上是正确的,但风格上非常错误。

    1. 您应尽可能使用with-open-file
    2. 您不应在代码中使用print,它是一种奇怪的遗留功能,主要用于交互式使用。
    3. 您无法使用setq创建局部变量 - 使用let或其他等效形式(在这种情况下,您永远不需要let!: - )
    4. 以下是重写函数的方法:

      (defun alphabets (input-file output-file)
        (with-open-stream (source input-file)
          (with-open-stream (code output-file :direction :output :if-exists :supersede)
            (loop for line = (read-line source nil nil)
                as num = (parse-integer line :junk-allowed t)
              while line do
                (when num
                  (write num :stream code)
                  (write-char #\Newline code))))))
      (alphabets "fr.txt" "alphabet_code.txt")
      

      参见文档:

      1. loopfor/aswhiledo
      2. writewrite-char
      3. parse-integer
      4. 或者,我可以使用相应的loop conditional代替(when num ...)

        此外,我可以写write而不是write-char + (format code "~D~%" num)

        请注意,我传递那些与默认值相同的with-open-stream参数。 默认设置是一成不变的,您编写的代码越少,用户必须阅读的内容越少,错误的可能性就越大。