如果我试试这个
(import java.util.regex.Pattern)
(Pattern/compile ")!@#$%^&*()")
或者
(def p #")!@#$%^&*()")
我有Clojure抱怨有一个无与伦比的/未闭合的)
。为什么在这个简单的字符串中评估括号?怎么逃避他们?感谢
编辑:虽然转义符合特定于语法的语法(#""
),但它无法使用我需要的Pattern/compile
语法,因为我必须从字符串动态编译正则表达式模式。
我尝试过使用re-pattern
,但出于某种原因我无法正常逃脱:
(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
编辑2 这个小功能可能会有所帮助:
(defn escape-all [x]
(str "\\" (reduce #(str %1 "\\" %2) x)))
答案 0 :(得分:10)
我通过双重逃避一切来实现它。哦,双重逃避的乐趣。
=> (re-pattern "\\)\\!\\@\\#\\$\\%\\^\\&\\*\\(\\)")
=> #"\)\!\@\#\$\%\^\&\*\(\)"
=> (re-find (re-pattern "\\)\\!\\@\\#\\$\\%\\^\\&\\*\\(\\)")
")!@#$%^&*()")
=> ")!@#$%^&*()"
我建议编写一个辅助函数str-to-pattern
(或者你想要的任何东西),它接受一个字符串,双重转义所需的一切,然后在其上调用re-pattern
。
编辑:制作字符串以模式化功能
有很多方法可以做到这一点,下面只是一个例子。我首先将正则表达式转义为字符串替换。 “smap”不是实际类型,但从功能上来说,它是一个我们将用“旧值”与“新值”交换的地图,其中“旧值”是smap键的成员,以及“新值”是相应的smap的成员。在我们的例子中,这个smap看起来像{\( "\\(", \) "\\)" ...}
。
(def regex-char-esc-smap
(let [esc-chars "()*&^%$#!"]
(zipmap esc-chars
(map #(str "\\" %) esc-chars))))
接下来是实际功能。我使用上面的smap替换传递给它的字符串中的项目,然后将其转换回字符串并从中生成正则表达式模式。我认为->>
宏使代码更具可读性,但这只是个人偏好。
(defn str-to-pattern
[string]
(->> string
(replace regex-char-esc-smap)
(reduce str)
re-pattern))
答案 1 :(得分:3)
你确定错误来自读者(即来自clojure本身)吗?
regexps使用括号,它们也必须匹配。我猜这个错误来自试图编译正则表达式的代码。
如果你想在正则表达式中逃避paren,请使用反引号:(def p #"\)!@#$%^&*\(\)")
[更新]啊,对不起,你可能需要像Omri那样双重逃脱。
答案 2 :(得分:2)
Clojure支持的所有Java版本都会识别\Q
以启动引用区域,\E
来结束引用区域。这允许你做这样的事情:
(re-find #"\Q)!@#$%^&*()\E" ")!@#$%^&*()")
如果你正在使用(re-pattern)
,那么这将有效:
(re-find (re-pattern "\\Q)!@#$%^&*()\\E") ")!@#$%^&*()")
如果您正在组装一个您不知道其内容的字符串的正则表达式,那么您可以使用quote
中的java.util.regex.Pattern
方法:
(re-find (re-pattern (java.util.regex.Pattern/quote some-str)) some-other-str)
以下是我的REPL的一个例子:
user> (def the-string ")!@#$%^&*()")
#'user/the-string
user> (re-find (re-pattern (java.util.regex.Pattern/quote the-string)) the-string)
")!@#$%^&*()"