我有一个包含有效Clojure表单的字符串。我想替换它的一部分,就像使用assoc-in
一样,但是将整个字符串作为标记处理。
=> (assoc-in [:a [:b :c]] [1 0] :new)
[:a [:new :c]]
=> (assoc-in [:a
[:b,, :c]] [1 0] :new)
[:a [:new :c]]
=> (string-assoc-in "[:a
[:b,, :c]]" [1 0] ":new")
"[:a
[:new,, :c]]"
我想写string-assoc-in
。请注意,它的第一个和最后一个参数是字符串,它保留换行符和逗号。它在Clojure中可行吗?我发现最接近的是read
,它会调用clojure.lang.LispReader
,但我不知道它是如何工作的。
我想用它来读取Clojure源文件,并通过一些修改显示它,保留文件的结构。
答案 0 :(得分:4)
或者另一个选择是将ANTLR到parse the Clojure代码用于AST,然后转换AST,然后导出回字符串。
答案 1 :(得分:2)
你可以用(read-string)和一些字符串操作的组合来做到这一点:
(defn string-assoc-in
[a b c]
(.replaceAll
(str
(assoc-in (read-string (.replaceAll a ",," ",_,")) b (read-string c)))
" _ " ",, "))
user> (string-assoc-in "[:a [:b,, :c]]" [1 0] ":new")
"[:a [:new,, :c]]"
请注意,我们需要一个您不希望在关键字中使用的保留占位符字符(在本例中为_)。诀窍在于,当读者在矢量字符串上进行处理时,将它们放在一边,然后将它们放回去。
此示例未解决换行符,但我认为您可以采用相同的方式处理这些换行符。
答案 2 :(得分:2)
我认为这应该有用,完全是通用的,不需要自己的读者/解析器:
(defn is-clojure-whitespace? [c]
(or (Character/isSpace c)
(= \, c)))
(defn whitespace-split
"Returns a map of true -> (maximal contiguous substrings of s
consisting of Clojure whitespace), false -> (as above, non-whitespace),
:starts-on-whitespace? -> (whether s starts on whitespace)."
[s]
(if (empty? s)
{}
(assoc (group-by (comp is-clojure-whitespace? first)
(map (partial apply str)
(partition-by is-clojure-whitespace? s)))
:starts-on-whitespace?
(if (is-clojure-whitespace? (first s)) true false))))
(defn string-assoc-in [s coords subst]
(let [{space-blocks true
starts-on-whitespace? :starts-on-whitespace?}
(whitespace-split s)
s-obj (assoc-in (binding [*read-eval* false] (read-string s))
coords
(binding [*read-eval* false] (read-string subst)))
{non-space-blocks false}
(whitespace-split (pr-str s-obj))]
(apply str
(if starts-on-whitespace?
(interleave space-blocks (concat non-space-blocks [nil]))
(interleave non-space-blocks (concat space-blocks [nil]))))))
示例:
user> (string-assoc-in "[:a [:b,, :c]]" [1 0] ":new")
"[:a [:new,, :c]]"
更新:哎呀,抓到了一个错误:
user> (string-assoc-in "[:a [:b,, :c\n]]" [1 0] ":new")
"[:a [:new,, :c]]\n"
如果没关系,我会喜欢它,但我想我必须尝试做点什么...... 叹息
答案 3 :(得分:1)
我假设您不想真正阅读表格并对其进行评估? fnparse有一个Clojure parser(使用fnparse用Clojure编写)。您可以使用它来从字符串到表单,然后操作,然后将其放回字符串?