使用读取行从.txt读取,读取其他符号。记事本的伪像?

时间:2019-07-16 08:57:35

标签: lisp common-lisp

以下是考试作业/准备工作的一部分:我正在尝试编写一些简明的代码,以从文本文件中读取行。空行应包括在内。以下是我想出的代码:

(defun read-file (filename)
   (do* ((streamin (open filename))               ;open the file
        content
        (line (read-line streamin nil 'eof)      ;read from file in loop
               (read-line streamin nil 'eof)))
        ((equal line 'eof) (close streamin)       ;close the stream if eof is reached
        (reverse content))
    (setq content (cons line content))))         ;add a read line to the returned symbol

在高级文本编辑器(或记事本)中创建的文本文件的预期输出,如下所示:

this is

a

test
file

是这个

("this is" "" "a" "" "test" "file")

但是,我收到以下消息:

("this is^M" "^M" "a^M" "^M" "test^M" "file^M")

“ ^ M”来自哪里?它们是通过记事本插入的吗?还是因为我的代码而在那里?他们到底是什么?我猜他们表明有新的一行。

如果它们是通过崇高插入的,那么我必须用什么替代方法来产生预期的输出?记事本也一样。练习的下一步是使用过滤器函数从输出中删除空行,我想通过将等于空行的行进行比较来实现此目的。但是,当插入这些^ M时,这是不可能的,因为例如

(equal "^M" (read-line test_file_with_empty_lines))

返回NIL。虽然

(equal "^M" "^M")

明显返回T ...

1 个答案:

答案 0 :(得分:6)

您正在使用DOS的行尾约定的系统读取文件,该系统需要Unix的行尾约定。

DOS用回车符/换行符对结束行。回车的ASCII码为#x0d / 13,即控件M,换行符为#x0a / 10,即控件J。

这些字符的CL名称(我应该在上面使用过)分别为#\Return#\Newline

因此,具有DOS行尾约定的文件将包含类似({十六进制)0d0a之类的序列以标记行尾。读完它的人会期望Unix的行尾约定(只是一个0a),然后将其读为最后一个字符为#\Return的行。

处理此问题的方法是三件事之一:

  • 假设您在Unixy机器上运行,请使用使用Unixy行尾约定的编辑器(无论如何,Sublime Text在OSX上都是如此);
  • 如果您使用的是Windows计算机,那么Lisp可能应该默认使用平台的本地行尾约定并为您翻译;
  • 如果以上一项或两项均不起作用,或者文件已在计算机之间移动,则需要阅读open的实现文档,以了解如何教其使用适当的外部格式来读取DOS常规文件。

似乎您正在使用CLISP。如果是这样,并且如果我正确阅读了其手册,则可能要使用(open ... :external-format ':dos)之类的东西。


另外要注意的是,尽管您的代码可以正常工作,但它不是非常惯用的CL,也不安全(读取文件时发生错误怎么办?):您可能希望查看规范的21.2节。 (出于您的诚实,我故意不给您答案,并表示这是家庭作业,谢谢!)。