2010-07-16 10 views
10

Stuart Halloway da el ejemplocódigo Clojure compacto para coincidencias de expresiones regulares y su posición en la cadena de

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

como el método natural para la búsqueda de coincidencias de partidos de expresiones regulares en Clojure. En su libro, esta construcción se contrasta con la iteración sobre un matcher. Si todo lo que le importaba fuera una lista de coincidencias, sería genial. Sin embargo, ¿qué pasa si quiero coincidencias y su posición dentro de la cadena? ¿Hay una forma mejor de hacer esto que me permita aprovechar la funcionalidad existente en java.util.regex y recurrir a algo así como una comprensión de secuencia sobre cada índice en la cadena original? En otras palabras, a uno le gustaría escribir algo así como

(re-ss-mapa # "[0-9] +" "3a1b2c1d")

que devolver un mapa con teclas como la posición y los valores como las coincidencias, por ejemplo

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

¿Hay alguna aplicación de este en una biblioteca existente ya o se lo escribo (no debe ser demasiado mayo de líneas de código)?

Respuesta

10

Puede recuperar los datos que desea de un objeto 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

Gracias Brian. Tal vez re-pos debe encontrar su camino en la biblioteca de expresiones regulares. –

+0

Tengo un pequeño problema con esto. (re-pos # "ATAT" "GATATATGCATATACTT") debería devolver {9 "ATAT", 3 "ATAT", 1 "ATAT"} pero devuelve {9 "ATAT", 1 "ATAT"}. – boucekv

+0

Si desea contar coincidencias superpuestas, cambie un poco la expresión regular: (re-pos # "(? = (ATAT))" "GATATATGCATATACTT" devuelve {9 "", 3 "", 1 ""}. Si desea recuperar el texto coincidente, debe hacer (.grupo m 1) en lugar de (.grupo m). –

1

Se puede aplicar cualquier función al objeto java.util.regex.Matcher y devolver los resultados (del mismo tipo que la solución de Brian, pero sin explícita 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"} 
Cuestiones relacionadas