2010-07-16 8 views
10

Stuart Halloway dà l'esempiocodice compatto Clojure per regolare le partite di espressione e la loro posizione nella stringa

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

come metodo naturale per trovare partite di partite regex in Clojure. Nel suo libro questa costruzione è in contrasto con l'iterazione su un matcher. Se a tutti fosse importato un elenco di partite, sarebbe fantastico. Tuttavia, che cosa succede se volevo corrispondenze e la loro posizione all'interno della stringa? C'è un modo migliore per farlo che mi consente di sfruttare la funzionalità esistente in java.util.regex ricorrendo a qualcosa come una comprensione di sequenza su ogni indice nella stringa originale? In altre parole, si vorrebbe digitare qualcosa come

(ri-Seq-map # "[0-9] +" "3a1b2c1d")

che sarebbe tornato una mappa con tasti come la posizione e i valori come le partite, ad es

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

C'è qualche attuazione del presente in una libreria esistente già o devo scriverlo (non dovrebbe essere troppo may linee di codice)?

risposta

10

È possibile recuperare i dati desiderati da un oggetto 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

Grazie Brian. Forse il re-pos dovrebbe trovare la sua strada nella libreria regex. –

+0

Ho un piccolo problema con questo. (re-pos # "ATAT" "GATATATGCATATACTT") dovrebbe restituire {9 "ATAT", 3 "ATAT", 1 "ATAT"} ma restituisce {9 "ATAT", 1 "ATAT"}. – boucekv

+0

Se si desidera contare le corrispondenze sovrapposte, modificare leggermente l'espressione regolare: (re-pos # "(? = (ATAT))" "GATATATGCATATACTT") restituisce {9 "", 3 "", 1 ""}. Se si desidera recuperare il testo abbinato, è necessario eseguire (.gruppo m 1) anziché (.gruppo m). –

1

È possibile applicare qualsiasi funzione all'oggetto java.util.regex.Matcher e restituire i suoi risultati (simili a soluzione di Brian, ma senza esplicito 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"} 
Problemi correlati