2012-07-26 8 views
5

Se provo questoEscaping parentesi Clojure

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

o questo

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

ho Clojure lamentando che ci sia un ineguagliabile/non chiusa ). Perché le parentesi sono valutate all'interno di questa semplice stringa? Come sfuggirli? Grazie

EDIT: Durante la fuga opere nella sintassi specifica per clojure (#""), non funziona con il Pattern/compile sintassi che ho bisogno perché devo compilare il picchiettio regex in modo dinamico da una stringa.

Ho provato con re-pattern, ma non posso sfuggire correttamente per qualche motivo:

(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 Questa piccola funzione potrebbe aiutare:

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

Per inciso, non penso che sia necessario importare, è sufficiente utilizzare la funzione 're-pattern' di Clojure. –

+0

hai ragione. ancora, non riesco a farlo funzionare. vedi la mia modifica, per favore. – pistacchio

risposta

10

L'ho ottenuto lavorando evitando il doppio tutto. Oh, le gioie della doppia fuga.

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

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

mi sento di raccomandare a scrivere una funzione di supporto str-to-pattern (o come volete chiamarlo), che prende una stringa, doppie fughe tutto ciò che ha bisogno di, e quindi chiama re-pattern su di esso.

Edit: fare una stringa di funzione di modello
Ci sono molti modi per farlo, di seguito è solo un esempio. Comincio facendo uno smap di regex escape char alla loro sostituzione di stringhe. Uno "smap" non è un tipo reale, ma funzionalmente è una mappa che utilizzeremo per scambiare "vecchi valori" con "nuovi valori", dove "vecchi valori" sono membri delle chiavi dello smap e "nuovi valori" sono membri corrispondenti dei vals di smap. Nel nostro caso, questo smap si presenta come {\("\\(", \) "\\)" ...}.

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

successivo è la funzione attuale. Uso lo smap di sopra per sostituire gli elementi nella stringa passata, quindi riconvertirlo in una stringa e creare un modello regex. Penso che la macro ->> renda il codice più leggibile, ma questa è solo una preferenza personale.

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

Sei sicuro che il l'errore è dal lettore (cioè dal clojure stesso)?

regexps utilizzano parentesi e devono corrispondere anche lì. direi che l'errore è dovuto al codice che tenta di compilare la regexp.

se si vuole sfuggire a una parentesi in un'espressione regolare, utilizzare un backquote: (def p #"\)[email protected]#$%^&*\(\)")

[update] ah, scusa, probabilmente avete bisogno di doppi fughe come giorni Omri.

+0

grazie, ma puoi vedere la mia modifica? – pistacchio

+0

@pistacchio Penso che dovrai scappare doppiamente. Potrei suggerire di scrivere una funzione di aiuto 'str-to-pattern' (o un nome simile) che prende una stringa, raddoppia le cose di cui ha bisogno e poi chiama' re-pattern' su di essa. –

+0

non riesco a trovare una tale funzione qui http://clojure.org/cheatsheet – pistacchio

1

Tutte le versioni di Java che supporta Clojure riconoscere \Q per avviare una regione citata e \E per terminare la regione citato.Questo ti permette di fare qualcosa di simile:

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

Se stai usando (re-pattern) allora questo lavoro:

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

Se stai assemblando un'espressione regolare da una stringa il cui contenuto si don' so quindi è possibile utilizzare il metodo quote in java.util.regex.Pattern:

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

Ecco un esempio di questo dal mio 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]#$%^&*()"