如何在没有双引号的情况下吐出列表

时间:2013-11-09 21:20:13

标签: clojure

我的代码中有以下行:

(spit path (prn-str job-data))

它确实很好地执行了一件事,列表中的每个项目都放在双引号之间......

( ":a" ":b" ":a" )

我想要的预期结果

( :a :b :a )

如何获得预期结果?

提前致谢!

2 个答案:

答案 0 :(得分:2)

发生了什么

问题不在于这些项目是双引号本身,而是它们是字符串(而不是您期望的关键字)。

prn-str,最终基于pr,以“读者可以读取对象的方式”打印对象。这意味着字符串以双引号打印 - 否则读者将无法从符号中分辨字符串,或读取其中包含空格的字符串。有关Clojure读者的更多信息,请参阅here

另一方面,

printlnprint旨在“为人类消费产生输出”,而不是将字符串放在双引号中。这就是为什么您看到prn-strprintln之间输出的差异。

您可以使用class验证这一点。如果您尝试(-> job-data first class),答案将为java.lang.Stringclojure.lang.Keyword

以下是一些示例,演示了与关键字和字符串一起使用时打印功能的不同行为:

(def str-job-data '(":a" ":b" ":c"))
(def key-job-data '(:a :b :c))

;; `println` prints both keywords and strings without quotes
(with-out-str (println str-job-data)) ;=> "(:a :b :c)\n"
(with-out-str (println key-job-data)) ;=> "(:a :b :c)\n"

;; `prn-str` prints the strings in quotes but the keywords without quotes
(prn-str str-job-data) ;=> "(\":a\" \":b\" \":c\")\n"
(prn-str key-job-data) ;=> "(:a :b :c)\n"

如何更改

现在寻找可能的解决方案。如果您希望job-data包含关键字,那么正确的修复最有可能修改job-data。但是,如果不了解job-data的生成方式,我无法提供更多指导。

如果出于某种原因你无法修改job-data(例如,如果它是由你无法控制的代码生成的),并且你想在任何地方写出类似关键字的字符串,那么像@ maxthoursie的建议可能是你最好的选择。 (您可以假设只是切换到printprintln,但这可能会对其他对象的打印方式产生不良影响。

(defn keyword-string->keyword [s]
  (keyword (subs s 1)))

(spit path (prn-str (map keyword-string->keyword job-data)))

如果job-data可能包含类似关键字的字符串以外的对象,则只能在适当的时候应用该函数。

(defn convert-job-data [obj]
  (if (and (string? obj)
           (= (.charAt obj 0) \:))
    (keyword-string->keyword obj)
    obj))

(spit path (prn-str (map convert-job-data job-data)))

当然,如果您正在撰写的文件仅供人类使用,并且所有与读者有关的业务都无关紧要,您可以轻松制作自己的println-str

(defn println-str [& more]
  (with-out-str (apply println more)))

(spit path (println-str job-data))

答案 1 :(得分:0)

我猜工作数据并不是你所期望的那样。

user=> (prn-str '(:a :b :c))
"(:a :b :c)\n"

如果您的列表中包含类似于关键字的字符串,并且您希望将其转换为关键字,则可以使用类似

的内容
 (map (comp keyword #(subs % 1)) '(":a" ":b" ":c"))

跳过每个元素的:然后将其转换为关键字。

user=> (prn-str (map (comp keyword #(subs % 1)) '(":a" ":b" ":c")))
"(:a :b :c)\n"