2010-07-16 18 views
10

Stuart Halloway cho ví dụđang Clojure nhỏ gọn cho trận đấu biểu thức chính quy và vị trí của họ trong chuỗi

(re-seq #"\w+" "The quick brown fox") 

như phương pháp tự nhiên cho việc tìm kiếm các trận đấu của các trận đấu regex trong Clojure. Trong cuốn sách của mình, công trình này được đối chiếu với sự lặp lại qua một người so khớp. Nếu tất cả mọi người quan tâm là một danh sách các trận đấu thì điều này thật tuyệt vời. Tuy nhiên, nếu tôi muốn các trận đấu và vị trí của họ trong chuỗi? Có cách nào tốt hơn để làm điều này cho phép tôi tận dụng các chức năng hiện có trong java.util.regex với việc sử dụng một cái gì đó giống như một chuỗi hiểu trên mỗi chỉ mục trong chuỗi ban đầu? Nói cách khác, người ta sẽ muốn gõ một cái gì đó giống như

(re-seq-đồ # "[0-9] +" "3a1b2c1d")

mà sẽ trả về một bản đồ với các phím như vị trí và giá trị như các kết quả phù hợp, ví dụ

{0 "3", 2 "1", 4 "2", 6 "1"} 

Có một số triển khai thực hiện điều này trong thư viện chưa có hoặc tôi có viết nó (không được quá dòng mã) không?

Trả lời

10

Bạn có thể tìm nạp dữ liệu mình muốn từ đối tượng java.util.regex.Matcher.

user> (defn re-pos [re s] 
     (loop [m (re-matcher re s) 
       res {}] 
      (if (.find m) 
      (recur m (assoc res (.start m) (.group m))) 
      res))) 
#'user/re-pos 
user> (re-pos #"\w+" "The quick brown fox") 
{16 "fox", 10 "brown", 4 "quick", 0 "The"} 
user> (re-pos #"[0-9]+" "3a1b2c1d") 
{6 "1", 4 "2", 2 "1", 0 "3"} 
+0

Cảm ơn Brian. Có lẽ tái pos nên tìm đường vào thư viện regex. –

+0

Tôi có một chút vấn đề với điều này. (re-pos # "ATAT" "GATATATGCATATACTT") phải trả về {9 "ATAT", 3 "ATAT", 1 "ATAT"} nhưng nó trả về {9 "ATAT", 1 "ATAT"}. – boucekv

+0

Nếu bạn muốn đếm các kết quả trùng lặp, hãy thay đổi regex một chút: (re-pos # "(? = (ATAT))" "GATATATGCATATACTT") trả về {9 "", 3 "", 1 ""}. Nếu bạn muốn lấy lại văn bản phù hợp, bạn cần phải làm (.group m 1) thay vì (.group m). –

1

Bạn có thể áp dụng bất kỳ chức năng để đối tượng java.util.regex.Matcher và trả về kết quả của nó (simmilar để giải pháp của Brian, nhưng không rõ ràng loop):

user=> (defn re-fun 
     [re s fun] 
     (let [matcher (re-matcher re s)] 
      (take-while some? (repeatedly #(if (.find matcher) (fun matcher) nil))))) 
#'user/re-fun 

user=> (defn fun1 [m] (vector (.start m) (.end m))) 
#'user/fun1 

user=> (re-fun #"[0-9]+" "3a1b2c1d" fun1) 
([0 1] [2 3] [4 5] [6 7]) 

user=> (defn re-seq-map 
     [re s] 
     (into {} (re-fun re s #(vector (.start %) (.group %))))) 

user=> (re-seq-map #"[0-9]+" "3a1b2c1d") 
{0 "3", 2 "1", 4 "2", 6 "1"} 
Các vấn đề liên quan