В clojure, как написать функцию, которая применяет несколько замен строк? - PullRequest
8 голосов
/ 05 марта 2012

Я хотел бы написать функцию replace-several, которая получает строку и набор замен и применяет все замены (где замены видят результат предыдущих замен).

Я думал о следующем интерфейсе:

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

Два вопроса:

  1. Это самый идиоматический интерфейс в clojure?
  2. Как реализовать эту функцию?

Примечание: для выполнения однократной замены доступно replace в clojure.string .

Ответы [ 7 ]

12 голосов
/ 05 марта 2012

Реализация совета @ kotarak с использованием replace, reduce и partition:

(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"
9 голосов
/ 05 марта 2012

Итак, у вас есть replace, reduce и partition. Из этих строительных блоков вы можете построить свой replace-several.

4 голосов
/ 19 марта 2015

Я опаздываю на эту вечеринку, но я думаю, что самый идиоматический способ сделать это - использовать многопоточность и множественные замены:

(require '[clojure.string :refer [replace])

(-> "abc"
    (replace #"a" "c")
    (replace #"b" "l")
    (replace #"c" "j"))

;=> "jlj"

Смысл этого вполне понятен, хотя было бы неплохо избегать многократного ввода «replace».

4 голосов
/ 05 марта 2012

Вот еще один снимок, но с различными результатами вывода , этот использует возможности движка regex, поэтому он может быть быстрее, также интерфейс другой, так как он сопоставляет ключи со строками замены.Я предоставляю это в случае, если это может быть полезно для кого-то с подобным вопросом.

(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"

1 голос
/ 07 марта 2012

Вы можете использовать уменьшить с заменить:

(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")
0 голосов
/ 31 августа 2017

Лично я бы не стал создавать для этого отдельную функцию, так как это просто набор существующих функций Clojure:

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

Конечно, если вы хотите varargs и интерфейс, то:

  1. Да, это кажется довольно идиоматическим
  2. Я бы реализовал это так:

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

0 голосов
/ 05 марта 2012

первое предположение ..

(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"
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...