5

ファイルを文字ごとに処理する関数をClojureで作成しています。Java の BufferedReader クラスに 1 文字を読み取る read() メソッドがあることは知っていますが、Clojure は初めてで、使い方がわかりません。現在、ファイルを行ごとに実行してから、各文字を印刷しようとしています。

(defn process_file [file_path]
(with-open [reader (BufferedReader. (FileReader. file_path))]
    (let [seq (line-seq reader)]
        (doseq [item seq]
            (let [words (split item #"\s")]
                (println words))))))

次のテキスト入力を含むファイルが与えられた場合:

国際的な寄付は喜んで受け入れられますが、米国外から受け取った寄付の税務上の取り扱いに関しては、いかなる声明も出すことはできません。米国の法律だけで、私たちの小さなスタッフが圧倒されます。

私の出力は次のようになります。

[International donations are gratefully accepted, but we cannot make]
[any statements concerning tax treatment of donations received from]
[outside the United States.  U.S. laws alone swamp our small staff.]

私はそれが次のようになることを期待していますが:

["international" "donations" "are" .... ]

私の質問は、上記の関数を文字単位で読み取るように変換するにはどうすればよいですか? または、期待どおりに機能させるにはどうすればよいですか?また、Clojure コードを改善するためのヒントがあれば大歓迎です。

4

3 に答える 3

5
(with-open [reader (clojure.java.io/reader "path/to/file")] ...

私はこの方法でreaderin clojure を取得することを好みます。そして、 とはcharacter by character、 のようなファイル アクセス レベルで、読み取るread数を制御できることを意味しますbytesか?

編集

@deterbが指摘したように、のソースコードを確認しましょうline-seq

(defn line-seq
  "Returns the lines of text from rdr as a lazy sequence of strings.
   rdr must implement java.io.BufferedReader."
  {:added "1.0"
   :static true}
  [^java.io.BufferedReader rdr]
  (when-let [line (.readLine rdr)]
    (cons line (lazy-seq (line-seq rdr)))))

私は偽造したchar-seq

 (defn char-seq 
   [^java.io.Reader rdr]
   (let [chr (.read rdr)]
     (if (>= chr 0)
     (cons chr (lazy-seq (char-seq rdr))))))

char-seqこれですべての文字がメモリに読み込まれることはわかっています[1] が、 を直接呼び出すことができることを示していると思い.readますBufferedReader。したがって、次のようにコードを記述できます。

(let [chr (.read rdr)]
  (if (>= chr 0)
    ;do your work here
  ))

あなたはどのように思いますか?

[1] @dimagog のコメントによると、char-seqすべての char をメモリに読み込まないでください。lazy-seq

于 2012-07-26T14:20:08.120 に答える
1

あなたはかなり近いです-文字列はシーケンスであることを覚えておいてください。 (concat "abc" "def")結果はシーケンスになります(\a \b \c \d \e \f)

mapcatこれにはもう 1 つの非常に便利な関数があります。マッピング fn をシーケンスに適用した結果を遅延連結します。これは、mapcatすべての行文字列を に変換した結果が、目的の文字seqの遅延シーケンスになることを意味します。

としてこれを行いました(mapcat seq (line-seq reader))

その他のアドバイス:

  • リーダーをclojure.java.io/reader作成するには、クラスを直接作成するのではなく、関数を使用することをお勧めします。
  • ファイルの読み取りと文字列の処理 (この場合は印刷) を互いに分離することを検討してください。句内で完全なファイル解析を維持することは重要ですがwithopen、コードを読み取るファイルの外で実際の処理コードをテストできることは非常に便利です。
  • 複数の (ネストされている可能性がある) シーケンスをナビゲートする場合は、 の使用を検討してforください。 forネストされた for ループ タイプのケースを適切に処理します。

    (take 100 (for [line (repeat "abc") char (seq line)] (prn char)))

  • prnデバッグ出力に使用します。ユーザー出力(ユーザーが通常気にしない特定の詳細を隠します)と比較して、実際の出力を提供します。

于 2012-07-26T16:03:50.300 に答える