如何在 Clojure 中创建 "replace-second" 函数?

How to create a "replace-second" function in Clojure?

(clojure.string/replace-first "a x x c d" #"x" "b" )) ; Replace first

如果我想替换上面字符串中的第二个 x 怎么办?

例如它可能是:

(let [n     #{1}
          s     "a x x x x c d"
          re    #"x"
          m     (re-find re s)
          xs    (s/split s re)
          vs    (conj (vec (take (dec (count xs)) (repeat m))) nil)
          replacement ".."]
        (apply str (interleave xs (map-indexed (fn [index v] (if (n index) replacement v)) vs))))

一个Matcher instance lets us iterate over the matches:

(defn replace-nth [input pattern n new-value]
  (let [m (re-matcher pattern input)]
    (loop [counter n]
      (if (.find m)
        (if (= counter 0)
          (str (subs input 0 (.start m))
               new-value
               (subs input (.end m)))
          (recur (dec counter)))
        input))))

(replace-nth "a x x c d" #"x" 1 "Mjao!")
;; => "a x Mjao! c d"

嗯,也许你可以妥协?

(-> "a x x c d"  
  (clojure.string/replace-first #"x" "_")
  (clojure.string/replace-first #"x" "b" )
  (clojure.string/replace-first #"_" "x"))

只要确保 _ 不能在字符串中即可。

:)

好的,再来一个(模块化的):

首先,要替换的范围的惰性序列:

(defn ranges [re s]
  (let [m (re-matcher re s)]
    (for [_ (range) :while (re-find m)]
      [(.start m) (.end m)])))

user> (ranges #"x" "a x x b x")
;;=> ([2 3] [4 5] [8 9])

然后范围替换函数:

(defn replace-range [[a b] repl s]
  (str (subs s 0 a) repl (subs s b)))

user> (replace-range [1 3] "REPLACED" "a b c d e f")

;;=> "aREPLACED c d e f"

然后你做任何你想做的事:

(let [s "a x x b x"]
  (map #(replace-range % "ZEE" s)
       (ranges #"x" s)))

;;=> ("a ZEE x b x" "a x ZEE b x" "a x x b ZEE")

(let [s "a x x b x"]
  (-> (ranges #"x" s)
      second
      (replace-range "REPLACED" s)))

;;=> "a x REPLACED b x"