使用Clojure的读取字符串读取字符串的“未读”部分

时间:2016-09-06 16:08:01

标签: clojure tokenize

Clojure(读取字符串)非常有用。

例如。

(read-string "{:a 1 :b 2} {:c 3 :d 4} [1 2 3]")

会给我第一个对象{:a 1 :b 2}

但我怎样才能得到其余的字符串ie。 "{:c 3 :d 4} [1 2 3]"

读者等同于restdrop

4 个答案:

答案 0 :(得分:4)

您可以将字符串包装在StringReader中,然后将其包裹在PushbackReader中,然后将read多次从该阅读器中包裹。

NB。下面的例子使用clojure.edn/read,因为它是一个仅用于处理纯数据的edn-only阅读器; clojure.core/read主要用于阅读代码,永远不会与不受信任的输入一起使用。

(require '[clojure.edn :as edn])

(def s "{:a 1 :b 2} {:c 3 :d 4} [1 2 3]")

;; Normally one would want to use with-open to close the reader,
;; but here we don't really care and we don't want to accidentally
;; close it before consuming the result:
(let [rdr (java.io.PushbackReader. (java.io.StringReader. s))
      sentinel (Object.)]      ; ← or just use ::eof as sentinel
  (take-while #(not= sentinel %)
              (repeatedly #(edn/read {:eof sentinel} rdr))))
;= ({:a 1, :b 2} {:c 3, :d 4} [1 2 3])

答案 1 :(得分:1)

https://stackoverflow.com/users/232707/michał-marczyk

应该接受的答案的ClojureScript版本
(require '[cljs.reader :as rdr])
(require '[cljs.tools.reader.reader-types :as reader-types])

(def s "{:a 1 :b 2} {:c 3 :d 4} [1 2 3]")

(let [pbr (reader-types/string-push-back-reader s)
      sentinel ::eof]
    (take-while #(not= sentinel %)
        (repeatedly #(rdr/read {:eof sentinel} pbr))))

答案 2 :(得分:0)

可能不是很惯用但很直白

(->> (str "(" "{:a 1 :b 2} {:c 3 :d 4} [1 2 3]" ")") 
     (read-string))

然后访问单个元素(您也可以使用括号)

答案 3 :(得分:0)

如果您在字符串中有列表,则可以通过read-string的选项保留它 -

(def str-list "({:a 1 :b 2} {:c 3 :d 4} [1 2 3])")

(read-string {:read-cond :preserve} str-list)
;;=> ({:a 1 :b 2} {:c 3 :d 4} [1 2 3])

可用选项的来源可以在read function的文档字符串中找到,即来自REPL的(source read)