我有一个.dat文件,里面有一些数据(文本,数字等)。该数据文件的结构采用信息块的形式,以包含短语“patch n”的行开头,其中n是块的编号:
patch 0
-----
-----
patch 1
-----
-----
-----
.
.
patch 3
-----
现在,我想重新排列块并将它们以新的顺序(与补丁号一起)写入另一个文件。此新订单在new-order = (3 1 0 2)
等列表中定义。此外,每个块的第一行(在初始文件中)的行号在诸如line-numbers = (0 24 134 210 520)
的列表中定义。
我的问题是在common-lisp中对此进行编码的好方法。我写了下面的代码,但是在将一些数据写入新文件之后,显然这个过程陷入无休止的循环,我不得不停止自己而不得到结果:
(with-open-file (out output-stream
:direction :output
:if-exists :new-version
:if-does-not-exist :create)
(with-open-file (in input-stream
:direction :input
:if-does-not-exist nil)
(let ((new-order (list 3 1 0 2)))
(dotimes (n (length new-order))
(loop for line = (read-line in nil 'eof)
for i from 1
do (when (<= (nth (nth n new-order) line-numbers)
i
(nth (1+ (nth n new-order)) line-numbers))
(format out "~a~%" line)))))))
这显然不是一种有效的方式,我想知道导致这个问题的原因是什么,最好的方法是什么?
答案 0 :(得分:2)
主要问题似乎是您需要在每次传递后重置文件位置。发生无限循环是因为您从不检查文件结束(并抑制信号)。
侧面提示:使用dolist
代替dotimes
和nth
构建。
如果您不想让 n 传递( n 是补丁的数量),并且您无法将所有内容保存在内存中,则可以编写补丁到临时文件,然后以所需的顺序连接它们。如果您还没有足够的磁盘空间,那么它就会成为一个就地排序问题,并且元素大小会有所不同,这需要更多一些。