2012-03-05 39 views
8

Tôi muốn viết một hàm replace-several nhận một chuỗi và một tập hợp các thay thế và áp dụng tất cả các thay thế (nơi thay thế xem kết quả của các thay thế trước đó).Trong clojure, làm thế nào để viết một hàm áp dụng một số thay thế chuỗi?

Tôi nghĩ về giao diện sau:

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

Hai câu hỏi:

  1. Đó có phải là giao diện thành ngữ nhất trong clojure?
  2. Cách triển khai chức năng này?

Lưu ý: Để thực hiện một thay thế duy nhất, có replace có sẵn trong clojure.string.

+0

Ý bạn là '(thay thế một số" abc "...'? – Zaz

+0

@Josh Tôi không hiểu câu hỏi của bạn – viebel

+0

Tôi đang nói rằng tôi nghĩ "d" trong "abd" là một lỗi đánh máy, phải không? Chắc chắn nó phải là '" abc "', hoặc hàm 'replace-some' mà bạn mô tả sẽ là kỳ quái. – Zaz

Trả lời

11

Thực hiện tư vấn @ kotarak bằng cách sử dụng replace, reducepartition:

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

Vì vậy, bạn có replace, reducepartition. Từ các khối xây dựng này, bạn có thể tạo replace-several của mình.

+0

Chỉ cần nhận thấy bạn có thể vượt qua một đối số 'val' để giảm chức năng, nếu nó không cho bình luận của bạn, tôi sẽ không bao giờ nhận ra! – djhworld

0

đầu tiên đoán ..

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

Tại sao không sử dụng 'reduce'? – viebel

+0

Xem bình luận của tôi để trả lời kotarak, tôi không nhận ra bạn có thể chuyển một đối số 'val' thành' reduce' để tích lũy kết quả – djhworld

4

Dưới đây là một bắn nhưng điều đó có kết quả đầu ra khác nhau, chương trình này sử dụng các tính năng của động cơ regex để nó có khả năng có thể nhanh hơn, giao diện cũng khác, vì nó ánh xạ các phím đến các chuỗi thay thế. Tôi cung cấp điều này trong trường hợp nó có thể hữu ích cho ai đó với một câu hỏi tương tự.

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

Vì vậy, việc sử dụng sẽ như vậy:

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

=> "CLJ"

1

Bạn có thể sử dụng giảm với thay thế:

(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

Nó khá giống với câu trả lời của tôi. Sự khác biệt duy nhất là bên trong giảm, tôi đã sử dụng 'apply' thay vì destructuring. – viebel

2

tôi đến trễ này đảng, nhưng đối với những gì nó có giá trị, tôi nghĩ rằng nhất cách thành ngữ để làm điều này sẽ là sử dụng thread ing và nhiều thay thế:

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

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

;=> "jlj" 

Ý nghĩa của điều này khá rõ ràng, mặc dù rất hay để tránh gõ "thay thế" nhiều lần.

0

Cá nhân tôi sẽ không tạo ra một chức năng riêng biệt cho điều này, vì nó chỉ là một phần của chức năng Clojure hiện:

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

Tất nhiên nếu bạn muốn varargs và một giao diện sau đó:

  1. Có vẻ như hợp lý thành ngữ
  2. tôi muốn thực hiện nó như sau:

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

Các vấn đề liên quan