当前位置: 首页 > 知识库问答 >
问题:

在Clojure中思考:避免简单字符串解析器的OOP

常坚
2023-03-14

我目前正在Clojure中实现一个小型解析器,它需要一个输入字符串,如:

aaa(bbb(ccc)ddd(eee))fff(ggg)hhh

并返回不包含括号内字符的字符串,即。

(bbb(ccc)ddd(eee))(ggg)

我编写了以下函数:

(defn- parse-str [input]
  (let [bracket (atom 0)
        output (atom [])]
     (doseq [ch (seq input)]
         (case ch
          \( (swap! bracket inc)
          \) (swap! bracket dec)
           nil)
         (if (or (> @bracket 0) (= ch \)))
           (swap! output conj ch))) 
    (apply str @output)))

这对我来说很有用:

(parse-str"aaa(bbb(ccc)ddd(eee))fff(ggg)hhh")

“(bbb(ccc)ddd(eee))(ggg)”

然而,我担心我的方法过于面向对象,因为它使用原子作为某种局部变量来保持解析器的当前状态。

是否可以从功能性更强的编程角度编写相同的函数?(避开原子?)

任何意见,以改善我的代码也表示感谢。

共有3个答案

酆勇
2023-03-14

这是函数的迭代版本;但它仍然是纯功能的。我发现这样的代码布局很容易阅读。记住,当使用递归时,总是先检查终止条件。

(defn parse-str [s]
  (loop [[x & xs] (seq s), acc [], depth 0]
    (cond
      (not x)      (clojure.string/join acc)
      (= x \()     (recur xs (conj acc x) (inc depth))
      (= x \))     (recur xs (conj acc x) (dec depth))
      (<= depth 0) (recur xs acc depth)
      :else        (recur xs (conj acc x) depth))))
米嘉禧
2023-03-14

在许多使用局部变量的情况下,您只需将任何变化的变量作为参数循环,从而使用递归而不是突变。

(defn- parse-str [input]
  ;; Instead of using atoms to hold the state, use parameters in loop
  (loop [output []
         bracket 0
         ;; The [ch & tail] syntax is called destructuring,
         ;; it means let ch be the first element of (seq input),
         ;; and tail the rest of the elements
         [ch & tail] (seq input)] 
    ;; If there's no elements left, ch will be nil, which is logical false
    (if ch
      (let [bracket* (case ch
                       \( (inc bracket)
                       \) (dec bracket)
                       bracket)
            output* (if (or (> bracket* 0) (= ch \)))
                      (conj output ch)
                      output)]
        ;; Recurse with the updated values
        (recur output* bracket* tail))
      ;; If there's no characters left, apply str to the output
      (apply str output))))
蓬新
2023-03-14

两种方法:可以使用显式递归或reduce。

(defn parse-str [input]
  (letfn [(parse [input bracket result]
            (if (seq input)
              (let [[ch & rest] input]
                (case ch
                  \( (recur rest (inc bracket) (conj result ch))
                  \) (recur rest (dec bracket) (conj result ch))
                  (recur rest bracket (if (> bracket 0)
                                        (conj result ch)
                                        result))))
              result))]
    (clojure.string/join (parse input 0 []))))


(defn parse-str [input]
  (clojure.string/join
   (second (reduce (fn [acc ch]
                     (let [[bracket result] acc]
                       (case ch
                         \( [(inc bracket) (conj result ch)]
                         \) [(dec bracket) (conj result ch)]
                         [bracket (if (> bracket 0)
                                    (conj result ch)
                                    result)])))
                   [0 []]
                   input))))
 类似资料:
  • 我有一个输入json字符串,其中包含几个已经转义的特殊字符和一些未转义的特殊字符(如en-dash/em-dash)。解析此json字符串(需要解析此字符串以检索对象数组)后,它将具有特殊字符的字符串转换为Unicode值(例如,将短划线字符转换为2013)。我的要求是不要转义任何特殊字符,并保持其他已转义字符不变。简单来说,在解析JSON字符串后,内容不应更改。 请建议一些方法来处理这个问题。

  • 我们正在使用dexguard,并且在dexguard项目中还具有以下设置。文本 我还尝试了提供res/值/字符串的变体。类似xml的: 和 等 在小路上。但字符串的键值正在变得模糊。 正在返回0。(其中key是字符串值)。 我也试过了 避免字符串OBF指令的正确方法是什么?

  • 问题内容: 我想问一个有关在Java中避免字符串重复的问题。 该 情境 是:以标签和属性像这样的一个XML: 使用JibX,此XML将在如下所示的类中进行编组/解组: 该程序是长时间的批处理,因此将创建,使用,复制产品对象。 好吧, 问题 是:当我使用 Eclipse内存分析器(MAT)之 类的软件分析执行时,我发现了几个重复的String。例如,在id属性中, PROD 值在2000个实例左右重

  • 问题内容: 我有这样的XML字符串 我遵循此帮助 用Java查询XML的最简单方法 我的代码: 我想获取味精节点值,但出现异常 我不会为这个简单的任务使用一些外部库。请指导我如何获取其他节点的值。谢谢 问题答案: 您不能将其重复用于多个调用,因为它会自动关闭。因此,您将获得IO异常。试试这个 编辑: 更好的方法是使用A解析您的XML并构建第一个(使用JAXP的DOM API),然后可以在多个XPa

  • 问题内容: 我正在处理一种加密货币RPC并接收json数据,如下所示: 使用Jsoncpp库或json11会将数字解析为。发生这种情况时,由于双重精度问题,结果为:。总的来说,这对金融交易来说是灾难性的,是不可接受的。 我已经有一个定点库,可以使用有效的字符串并将其在内部视为整数。有没有一种方法可以使Jsoncpp(或其他任何json库)将选定的数字json值用作字符串,以便可以使用固定精度正确地

  • 我正在尝试转义字符串中的XML特殊字符。转义由静态方法处理,如下所示。 现在,这种实现的问题是,我得到了一段字符串,它可能被解析,也可能不被解析。这导致输出不规则。 例如: 现在,为了得到正确的响应,我计划在静态方法中引入一个检查。通过使用if条件,如下所示。 这是一种正确的实施方式吗?如果不是,请提出建议?