【问题标题】:In clojure, how to write a function that applies several string replacements?在clojure中,如何编写一个应用多个字符串替换的函数?
【发布时间】:2012-03-05 14:11:36
【问题描述】:

我想编写一个函数replace-several,它接收一个字符串和一组替换并应用所有替换(替换看到之前替换的结果)。

我想到了如下界面:

(replace-several "abc" #"a" "c" 
                       #"b" "l"
                       #"c" "j"); should return "jlj" 

两个问题:

  1. 它是 clojure 中最惯用的接口吗?
  2. 如何实现这个功能?

备注:要进行单次替换,clojure.string 中有replace

【问题讨论】:

  • 你的意思是(replace-several "abc" ...
  • @Josh 我不明白你的问题
  • 我是说我认为"abd" 中的“d”是一个错字,对吧?当然应该是"abc",否则你描述的replace-several函数会很奇怪。
  • 谢谢@Josh。你是绝对正确的。实际上,我的回答是正确的:)

标签: clojure


【解决方案1】:

使用replacereducepartition 实施@kotarak 的建议:

(defn replace-several [content & replacements]
      (let [replacement-list (partition 2 replacements)]
        (reduce #(apply string/replace %1 %2) content replacement-list)))
; => (replace-several "abc" #"a" "c" #"b" "l" #"c" "j")
  "jlj"

【讨论】:

    【解决方案2】:

    所以你有replacereducepartition。从这些构建块中,您可以构建您的replace-several

    【讨论】:

    • 刚刚注意到您可以将val 参数传递给reduce 函数,如果不是您的评论,我永远不会意识到!
    【解决方案3】:

    这是另一个镜头,但有不同的输出结果,这个镜头使用正则表达式引擎功能,因此它可能更快,而且界面也不同,因为它将键映射到替换字符串。我提供这个以防它对有类似问题的人有用。

    (defn replace-map
      "given an input string and a hash-map, returns a new string with all
      keys in map found in input replaced with the value of the key"
      [s m]
      (clojure.string/replace s
                  (re-pattern (apply str (interpose "|" (map #(java.util.regex.Pattern/quote %) (keys m)))))
              m))
    

    所以用法是这样的:

     (replace-map "abc" {"a" "c" "b" "l" "c" "j"})
    

    => "clj"

    【讨论】:

    • 感谢您提供此代码,正是我想要的。还不太懂你的代码,但我试过这个:(replace-map "this is a test to check if it functions as expected" {"this is" "htis si" "check if" "hceck fi" "functions as expected" "whatever"}),效果很棒!
    • 如果您想知道它是如何工作的,我正在创建一个由地图键组成的正则表达式。 clojure.string/replace 将使用该正则表达式并将匹配传递给m,它充当一个函数。由于m 已经是您要替换的映射,因此它将返回正确的替换。
    【解决方案4】:

    我迟到了,但就其价值而言,我认为惯用的方法是使用线程和多个替换:

    (require '[clojure.string :refer [replace])
    
    (-> "abc"
        (replace #"a" "c")
        (replace #"b" "l")
        (replace #"c" "j"))
    
    ;=> "jlj"
    

    这个意思很清楚,不过最好避免多次输入“replace”。

    【讨论】:

      【解决方案5】:
      (str/escape "abc" {\a "c" \b "l" \c "j"})
      
      ; => "clj"
      

      文档escape

      【讨论】:

      • 感谢这块金子。我完全错过了escape。非常好。将其添加到箭袋中。
      【解决方案6】:

      你可以使用reduce和replace:

      (defn replace-several
        [str & replacements]
        (reduce (fn [s [a b]]
                  (clojure.string/replace s a b))
                str
                (partition 2 replacements)))
      
      (replace-several "abc"
                       #"a" "c"
                       #"b" "l"
                       #"c" "j")
      

      【讨论】:

      • 和我的回答差不多。唯一的区别是在reduce内部,我使用apply而不是解构。
      【解决方案7】:

      第一个猜测..

      (defn replace-several [string & mappings]
        (loop [grouped-mappings (partition 2 mappings) string string]
          (if (empty? grouped-mappings)
            string
            (let [[re rep] (first grouped-mappings)]
              (recur (rest grouped-mappings) (clojure.string/replace string re rep))))))
      ; => (replace-several "abc" #"a" "c" #"b" "l" #"c" "j")
        "jlj"
      

      【讨论】:

      • 查看我对 kotarak 的回复,我没有意识到您可以将 val 参数传递给 reduce 以累积结果
      【解决方案8】:

      我个人不会为此创建单独的函数,因为它只是现有 Clojure 函数的组合:

      (reduce-kv clojure.string/replace "Hello" {#"[A-Z]" "J", "o" "y"} ;=> "Jelly"

      当然,如果你想要可变参数和接口,那么:

      1. 是的,它看起来相当地道
      2. 我会这样实现它:

      (defn replace-many [string & {:as rplcmnts}] (reduce-kv clojure.string/replace string rplcmnts))

      【讨论】:

        猜你喜欢
        • 2015-05-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-07-15
        • 1970-01-01
        • 2012-10-04
        • 2023-03-03
        • 1970-01-01
        相关资源
        最近更新 更多