2

フラットファイルの行数を数えたいので、次のコードを記述しました。

(defun ff-rows (dir file)
  (with-open-file (str (make-pathname :name file
                                      :directory dir)
                                      :direction :input)
    (let ((rownum 0))
      (do ((line (read-line str file nil 'eof)
                 (read-line str file nil 'eof)))
          ((eql line 'eof) rownum)
        (incf rownum )))))

ただし、エラーが発生します。

*** - READ: input stream
       #<INPUT BUFFERED FILE-STREAM CHARACTER #P"/home/lambda/Documents/flatfile"
         @4>
      ends within an object

ここで何が問題なのか聞いてもいいですか?行を数えてみました。この操作は問題ありません。

注:関数のテストに使用したフラットファイルの内容は次のとおりです。

2 3 4 6 2 
1 2 3 1 2
2 3 4 1 6
4

3 に答える 3

4

少し短いです。

(defun ff-rows (dir file)
  (with-open-file (stream (make-pathname :name file
                                         :directory dir)
                          :direction :input)
    (loop for line = (read-line stream nil nil)
          while line count line)))

正しい引数を取得する必要があることに注意してくださいREAD-LINE。最初はストリームです。ファイルはパラメータリストの一部ではありません。

また、一般的に、パス名の処理を一般的なLisp関数に混在させることはお勧めできません。

(defun ff-rows (pathname)
  (with-open-file (stream pathname :direction :input)
    (loop for line = (read-line stream nil nil)
          while line count line)))

別の関数または他のコードでパス名の処理を行います。パス名コンポーネントを関数に渡すことは、通常、間違った設計です。完全なパス名を渡します。

LispWorksファイルセレクターの使用:

CL-USER 2 > (ff-rows (capi:prompt-for-file "some file"))
27955

さらに良いのは、すべての基本的なI / O関数がパス名ではなく、ストリームで機能する場合です。したがって、ネットワークストリーム、シリアルライン、またはその他のストリームの回線をカウントできます。

于 2012-11-15T13:14:34.340 に答える
4

問題は、私が知る限り、(read-line ...)呼び出しの「ファイル」です。

ハイパースペックに基づくと、read-lineのシグネチャは次のとおりです。

read-line &optional input-stream eof-error-p eof-value recursive-p
=> line, missing-newline-p

...これは、「ファイル」がeof-error-pとして、nilがeof-valueとして、'eofがrecursive-pとして解釈されることを意味します。言うまでもなく、問題が発生します。読み取り行の呼び出しから「ファイル」を削除すると(たとえば(read-line str nil :eof))、コードは私のマシン(AllegroCL&LispWorks)でさらに変更を加えることなく正常に実行されます。

于 2012-11-15T12:19:24.797 に答える
1
(defun ff-rows (dir file)
  (with-open-file
      (str (make-pathname :name file :directory dir)
           :direction :input)
    (let ((result 0))
      (handler-case
          (loop (progn (incf result) (read-line str)))
        (end-of-file () (1- result))
        (error () result)))))

さて、もちろん、あなたが私よりも衒学者であれば、どのような種類のエラーを正確に処理したいかを指定することができますが、簡単な例ではこれで十分です。

編集:@Moritzは質問にもっとよく答えたと思いますが、それでもこれは、スローされたエラーread-lineを回避しようとするのではなく、有利に使用する方法の例である可能性があります。

于 2012-11-15T11:46:31.157 に答える