【问题标题】:Trouble with building up a string in Clojure在 Clojure 中构建字符串时遇到问题
【发布时间】:2011-06-05 22:13:52
【问题描述】:

[这似乎是 Compojure 的问题,但不是 - 它是 Clojure 的问题]

在这个看似简单的问题上,我一直在努力解决问题 - 但无济于事。

我正在使用 Compojure(Clojure 的轻量级 Web 框架),我只想生成一个网页,显示我在 PostgreSQL 数据库中的待办事项列表。

代码 sn-ps 如下(省略了数据库连接、查询等 - 但不需要该部分,因为具体问题是生成的 HTML 在

和 标记之间不显示任何内容) .

作为测试,我尝试在对 main-layout 的调用中对字符串进行硬编码,如下所示: (html (main-layout "Aki's Todos" "Haircut
Study Clojure
Answer a question on Stackoverfolw")) - 它工作正常。

所以真正的问题是我不相信我知道如何在 Clojure 中构建字符串。不是惯用的方式,也不是通过调用 Java 的 StringBuilder ——正如我在下面的代码中尝试做的那样。

一款虚拟啤酒,给能解决这个问题的人点赞!非常感谢!

================================================ ===============


;The master template (a very simple POC for now, but can expand on it later)

(defn main-layout
  "This is one of the html layouts for the pages assets - just like a master page"
  [title body]
  (html
    [:html
    [:head
      [:title title]
      (include-js "todos.js")
      (include-css "todos.css")]
    [:body body]]))


(defn show-all-todos 
  "This function will generate the todos HTML table and call the layout function"
  []
  (let [rs (select-all-todos)
       sbHTML (new StringBuilder)]
    (for [rec rs]
      (.append sbHTML (str rec "<br><br>"))) 
    (html (main-layout "Aki's Todos" (.toString sbHTML)))))

================================================ ===============

同样,结果是一个网页,但正文标签之间没有任何内容。如果我用 println 语句替换 for 循环中的代码,并将代码定向到 repl - 忘记网页内容(即对 main-layout 的调用),结果集将被打印 - 但是 - 问题在于构建上弦。

再次感谢。

~阿基

【问题讨论】:

  • 致 Gorgan Jovic - 抱歉,我删除了最后一个问题“我如何循环遍历结果集并在 Clojure 中建立一个字符串”并将其替换为这个问题。我试图找到一种方法来通知你,但不能。在回答您的问题“什么是'选择所有待办事项'返回”时,它是一个惰性序列 - 待办事项的结果集。每个项目有 8 个字段(一个 clojure 映射)。我可以通过在 for 循环中使用 println 语句将结果集打印到 repl - 但我想要做的是构建一个字符串,并将字符串传递给 main-layout 函数,以便它可以流式传输到浏览器。

标签: clojure


【解决方案1】:

for 是懒惰的,在你的函数中它永远不会被评估。将for 更改为doseq

user> (let [rs ["foo" "bar"] 
            sbHTML (new StringBuilder)]
        (for [rec rs]
          (.append sbHTML (str rec "<br><br>")))
        (.toString sbHTML))
""
user> (let [rs ["foo" "bar"] 
            sbHTML (new StringBuilder)]
        (doseq [rec rs]
          (.append sbHTML (str rec "<br><br>")))
        (.toString sbHTML))
"foo<br><br>bar<br><br>"

您也可以使用reduceinterpose,或者clojure.string/join 来自clojure.string,或者其他一些选项。

user> (let [rs ["foo" "bar"]]
            (reduce str (interpose "<br><br>" rs)))
"foo<br><br>bar"
user> (require 'clojure.string)
nil
user> (let [rs ["foo" "bar"]]
            (clojure.string/join "<br><br>" rs))
"foo<br><br>bar"

【讨论】:

  • 谢谢布赖恩!我不知道为什么使用'doseq'有效而'for'没有 - 特别是当'for'用于将记录打印到repl时。无论如何,我很高兴有一个解决方案。我喜欢 Clojure - 但它绝对有很高的学习曲线。再次感谢。 〜Aki PS。我无法使用 interpose 或 clojure.string/join,因为我需要稍微操作数据并在字段周围放置 html 表标签(tr、td 等)——但至少现在我可以遍历结果集。
  • 'for' 是惰性的,这意味着在需要结果之前它不会执行。从 repl 调用代码时,它将强制执行代码,因为它需要结果来打印它们。对于任何惰性序列都是如此。
【解决方案2】:

您想像这样使用re-gsub

(require 'clojure.contrib.str-utils) ;;放在 head 以便我们以后可以使用 re-gsub

(clojure.contrib.str-utils/re-gsub #"\newline" "

" your-string-with-todos-separated-with-newlines)

最后一行将生成您喜欢的字符串。正如您可能已经知道的那样,require 部分是为了使编译器能够访问强大的 clojure.contrib.str-utils 库,而无需将其导入当前的命名空间(这可能会在程序增长时导致不必要的冲突)。

re- 用于 reg-exp,并允许您定义形式为 #"regexp" 的 reg-exp,它将所有被 regexp 命中的实例替换为之后的参数,应用于第三个参数。在这种情况下,\newline 是 clojures 在正则表达式中表达换行符以及字符串和我们正在寻找的字符的方式。

我认为您真正想做的是以 html 格式制作一个漂亮的有序或无序列表。这些可以通过 [hiccup-page-helpers][2] 来完成(如果你没有它们,你可能在它被拆分为 compojure、打嗝等之前就有了一个 compojure,因为你使用了 html-function )。

如果你想使用 hiccup-page-helpers,使用命令 re-split 从上面提到的 clojure.contrib.str-utils 以这种方式:

(use 'hiccup.page-helpers) ;;注意命名空间冲突,因为 hiccup.page-helpers 中的所有函数都进入了你当前的命名空间。

(无序列表 (clojure.contrib.str-utils/re-split #"\newline" your-string-with-todos-separated-with-newlines))

它应该呈现一个整洁的


     
  • 待办事项1

  •  
  • 待办事项2

(是的,有一个以相同方式工作的有序列表命令!)

在上面的 clojure 代码的最后一行中,所有待办事项都进入了一个 (list "todo1" "todo2"),它会立即被 hiccup.page-helpers 无序列表函数消耗,并在那里转换为 html 化的列表。

祝你和朋友们好运!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-02-09
    • 2012-04-15
    • 1970-01-01
    • 2014-11-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-03
    相关资源
    最近更新 更多