Escaping brackets in Clojure

clojure, regex, string

Solution

I got it working by double escaping everything. Oh the joys of double escaping.

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

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

I would recommend writing a helper function `str-to-pattern` (or whatever you want to call it), that takes a string, double escapes everything it needs to, and then calls `re-pattern` on it.

Edit: making a string to pattern function There are plenty of ways to do this, below is just one example. I start by making an smap of regex escape chars to their string replacement. An "smap" isn't an actual type, but functionally it's a map we will use to swap "old values" with "new values", where "old values" are members of the keys of the smap, and "new values" are corresponding members of the vals of smap. In our case, this smap looks like `{\( "\\(", \) "\\)" ...}`.

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

Next is the actual function. I use the above smap to replace items in the string passed to it, then convert that back into a string and make a regex pattern out of it. I think the `->>` macro makes the code more readable, but that's just a personal preference.

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

Problem

If I try this ``` (import java.util.regex.Pattern) (Pattern/compile ")!@#$%^&*()") ``` or this ``` (def p #")!@#$%^&*()") ``` I have Clojure complaining that there is an unmatched / unclosed `)`. Why are brackets evaluated within this simple string? How to escape them? Thanks EDIT: While escaping works in the clojure-specific syntax (`#""`), it doesn't work with the `Pattern/compile` syntax that I do need because I have to compile the regex patter dynamically from a string. I've tried with `re-pattern`, but I can't escape properly for some reason: ``` (re-pattern "\)!@#$%^&*\(\)") 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 This little function may help: ``` (defn escape-all [x] (str "\\" (reduce #(str %1 "\\" %2) x))) ```

Original source