试图将 Clojure 运行 中的字符串拆分为惰性序列问题

Trying to split string in Clojure running into lazy seq problem

我正在解决一个问题,以读取包含以下行的文件:

A abcdefg
B bcdefgh

但我不断收到关于 Lazy Sequence 与 Java Charseq 不兼容的错误 ..

我试过了:

(def notlazy (doall lyne2))

然后以为我验证了:

(realized? notlazy)
true

但仍然:

(str/split notlazy #" ")
ClassCastException class clojure.lang.LazySeq cannot be cast to class
  java.lang.CharSequence (clojure.lang.LazySeq is in unnamed module of
  loader 'app'; java.lang.CharSequence is in module java.base of loader
  'bootstrap')  clojure.string/split (string.clj:219)

请帮忙!

str/split 的第一个参数必须是要拆分的 CharSequence。据推测,您希望拆分序列中的每个输入行,您可以使用 map 而无需急切地评估输入序列:

(map (fn [line] (str/split line #" ")) lyne2)

稍微扩展一下之前的结果,我们有这个例子。您可以使用 this template project.

重现以下内容
(ns tst.demo.core
  (:use demo.core tupelo.core tupelo.test)
  (:require
    [clojure.java.io :as io]
    [tupelo.string :as str]
    ))

(def data-file
  "A abcdefg
   B    bcdefgh
  ")

(dotest
  ; Version #1
  (let [lines      (line-seq (io/reader (str/string->stream data-file)))
        lines2     (remove str/blank? lines)
        lines3     (map str/trim lines2)
        line-words (mapv #(str/split % #"\s+") lines3) ; "\s+" => "one or more whitespace chars"
        ]
    (spyxx lines)
    (spyxx lines2)
    (spyxx lines3)
    (spyxx line-words))

结果:

--------------------------------------
   Clojure 1.10.2-alpha1    Java 15
--------------------------------------

Testing tst.demo.core
lines       => <#clojure.lang.Cons ("A abcdefg" "   B    bcdefgh" "  ")>
lines2      => <#clojure.lang.LazySeq ("A abcdefg" "   B    bcdefgh")>
lines3      => <#clojure.lang.LazySeq ("A abcdefg" "B    bcdefgh")>
line-words  => <#clojure.lang.PersistentVector [["A" "abcdefg"] ["B" "bcdefgh"]]>

这会显示每个结果的类型及其值。我们使用 string->stream 所以我们不需要设置一个虚拟文件来读取。

下面显示了它通常是如何用真实代码编写的(不是像版本 #1 那样的演示练习)。我们使用“thread-last”运算符,并编写单元测试来验证结果:

  ; Version #2
  (let [result (->> data-file
                 (str/string->stream)
                 (io/reader)
                 (line-seq)
                 (remove str/blank?)
                 (map str/trim)
                 (mapv #(str/split % #"\s+"))) ; "\s+" => "one or more whitespace chars"
        ]
    (is= result [["A" "abcdefg"] ["B" "bcdefgh"]])))