我正在尝试使用Clojure编写代码,需要实现以下算法:
从输入流中读取字符,直到不是分隔符为止。
在Java中可以使用while循环轻松实现,但是我不知道如何在Clojure中实现?
while read readChar != delimiter do some processing.... end while
我正在尝试使用Clojure编写代码,需要实现以下算法:
从输入流中读取字符,直到不是分隔符为止。
在Java中可以使用while循环轻松实现,但是我不知道如何在Clojure中实现?
while read readChar != delimiter do some processing.... end while
我不了解Clojure,但是它看起来像Scheme一样支持"let循环":
(loop [char (readChar)]
(if (= char delimiter)
'()
(do (some-processing)
(recur (readChar)))))
希望这足以让您开始。我参考了http://clojure.org/special_forms#toc9来回答这个问题。
注意:我知道Clojure不鼓励副作用,因此您可能希望返回有用的东西而不是'()。
在Clojure 1.3.0上工作,值得一提的是,现在你可以通过类似以下方式编写while循环:
(while truth-expression
(call-some-function))
(require '[clojure.java [io :as io]])
(defn char-seq
"create a lazy sequence of characters from an input stream"
[i-stream]
(map char
(take-while
(partial not= -1)
(repeatedly #(.read i-stream)))))
;; process the sequence one token at a time
;; with-open will automatically close the stream for us
(with-open [is (io/input-stream "/etc/passwd")]
(doseq [c (take-while (partial not= \:) (char-seq is))]
;; your processing is done here
(prn c)))
line-seq
的精神下想出了这个方法。它完全是懒加载的,表现出了 Clojure 更多的函数式特性,而不是 loop
。(defn delim-seq
([#^java.io.Reader rdr #^Character delim]
(delim-seq rdr delim (StringBuilder.)))
([#^java.io.Reader rdr #^Character delim #^StringBuilder buf]
(lazy-seq
(let [ch (.read rdr)]
(when-not (= ch -1)
(if (= (char ch) delim)
(cons (str buf) (delim-seq rdr delim))
(delim-seq rdr delim (doto buf (.append (char ch))))))))))
完整粘贴。
while循环通常涉及可变变量,即等待变量满足某个条件; 在Clojure中,您通常会使用尾递归(编译器将其转换为while循环)
以下不是完全的解决方案,但for循环的这种变体在某些情况下可能有所帮助:
(for [a (range 100)
b (range 100)
:while (< (* a b) 1000)]
[a b]
)
这将创建一个包含所有 a 和 b 的对的列表,直到 (< (* a b) 1000)
。也就是说,它会在满足条件时立即停止。如果你用 :when 替换 :while,那么它会找到所有满足条件的对,即使在找到不满足条件的对后。
我推出了这个版本:
(defn read-until
[^java.io.Reader rdr ^String delim]
(let [^java.lang.StringBuilder salida (StringBuilder.) ]
(while
(not (.endsWith (.toString salida) delim))
(.append salida (str (char (.read rdr))))
)
(.toString salida)
)
)
它寻找的是字符串,而不是单个字符作为分隔符!
谢谢!