2012-07-26 8 views
5

si intento estasoportes que se escapan en Clojure

(import java.util.regex.Pattern) 
(Pattern/compile ")[email protected]#$%^&*()") 

o esta

(def p #")[email protected]#$%^&*()") 

He Clojure quejaba de que hay una inigualable/no cerrada ). ¿Por qué se evalúan los corchetes dentro de esta cadena simple? ¿Cómo escapar de ellos? Gracias

EDITAR: Mientras escapaba obras en la sintaxis de la clojure específica (#""), que no funciona con la sintaxis Pattern/compile que yo necesito porque tengo que compilar el golpeteo expresión regular dinámicamente a partir de una cadena.

He tratado con re-pattern, pero no puedo escapar adecuadamente por alguna razón:

(re-pattern "\)[email protected]#$%^&*\(\)") 
    java.lang.Exception: Unsupported escape character: \) 
    java.lang.Exception: Unable to resolve symbol: ! in this context (NO_SOURCE_FILE:0) 
    java.lang.Exception: No dispatch macro for: $ 
    java.lang.Exception: Unable to resolve symbol: % in this context (NO_SOURCE_FILE:0) 
    java.lang.IllegalArgumentException: Metadata can only be applied to IMetas 

EDIT 2 Esta pequeña función puede ayudar a:

(defn escape-all [x] 
    (str "\\" (reduce #(str %1 "\\" %2) x))) 
+1

Como nota aparte, no creo que necesite la importación, solo podría usar la función 're-pattern' de Clojure. –

+0

tienes razón. aún así, no puedo hacer que funcione. ver mi edición, por favor. – pistacchio

Respuesta

10

Lo he conseguido escapando por partida doble. Oh las alegrías del doble escape.

=> (re-pattern "\\)\\!\\@\\#\\$\\%\\^\\&\\*\\(\\)") 
=> #"\)\!\@\#\$\%\^\&\*\(\)" 

=> (re-find (re-pattern "\\)\\!\\@\\#\\$\\%\\^\\&\\*\\(\\)") 
      ")[email protected]#$%^&*()") 
=> ")[email protected]#$%^&*()" 

recomendaría escribir una función auxiliar str-to-pattern (o como se quiera llamar), que toma una cadena, dobles escapes todo lo necesario para, a continuación, llama re-pattern en él.

Editar: hacer una cadena a la función de patrón de
Hay un montón de maneras de hacer esto, a continuación es sólo un ejemplo. Comienzo por hacer una pequeña cantidad de caracteres de escape de expresiones regulares para su reemplazo de cadena. Un "smap" no es un tipo real, pero funcionalmente es un mapa que usaremos para cambiar "valores antiguos" por "valores nuevos", donde "valores antiguos" son miembros de las teclas de smap y "valores nuevos" son miembros correspondientes de los vals de smap. En nuestro caso, esta smap se ve como {\("\\(", \) "\\)" ...}.

(def regex-char-esc-smap 
    (let [esc-chars "()*&^%$#!"] 
    (zipmap esc-chars 
      (map #(str "\\" %) esc-chars)))) 

Siguiente es la función real. Uso el smap anterior para reemplazar los elementos de la cadena que se le pasó, luego lo vuelvo a convertir en una cadena y hago un patrón de expresión regular. Creo que la macro ->> hace que el código sea más legible, pero eso es solo una preferencia personal.

(defn str-to-pattern 
    [string] 
    (->> string 
     (replace regex-char-esc-smap) 
     (reduce str) 
     re-pattern)) 
3

son el Seguro el error es del lector (es decir, de clojure sí mismo)?

regexps usan paréntesis, y tienen que coincidir allí también. Supongo que el error proviene del código que intenta compilar la expresión regular.

si quieres escapar de una paren en una expresión regular, utilizan una comilla inversa: (def p #"\)[email protected]#$%^&*\(\)")

[Actualización] Ah, lo siento, es probable que tenga escapes dobles como Omri días.

+0

gracias, pero ¿pueden ver mi edición? – pistacchio

+0

@pistacchio Creo que tendrás que escapar por partida doble. Podría sugerir escribir una función de ayuda 'str-to-pattern' (o algún nombre similar) que tome una cadena, doble escape de las cosas que necesita, y luego llama' re-pattern' en él. –

+0

no puedo encontrar tal función aquí http://clojure.org/cheatsheet – pistacchio

1

Todas las versiones de Java que soporta Clojure reconocer \Q para iniciar una región citado y \E para poner fin a la región citada.Esto le permite hacer algo como esto:

(re-find #"\Q)[email protected]#$%^&*()\E" ")[email protected]#$%^&*()") 

Si está utilizando (re-pattern) entonces esto va a trabajar:

(re-find (re-pattern "\\Q)[email protected]#$%^&*()\\E") ")[email protected]#$%^&*()") 

Si va a montar una expresión regular de una cadena cuyo contenido usted don' sé, puede utilizar el método quote en java.util.regex.Pattern:

(re-find (re-pattern (java.util.regex.Pattern/quote some-str)) some-other-str) 

He aquí un ejemplo de esto en mi REPL:

user> (def the-string ")[email protected]#$%^&*()") 
#'user/the-string 
user> (re-find (re-pattern (java.util.regex.Pattern/quote the-string)) the-string) 
")[email protected]#$%^&*()" 
Cuestiones relacionadas