6

如果我试试这个

(import java.util.regex.Pattern)
(Pattern/compile ")!@#$%^&*()")

或这个

(def p #")!@#$%^&*()")

我有 Clojure 抱怨有一个 unmatched / unclosed )。为什么要在这个简单的字符串中评估括号?如何逃脱他们?谢谢

编辑:虽然转义适用于 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)))
4

3 回答 3

12

我通过双重转义一切来让它工作。哦,双重逃脱的乐趣。

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

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

我建议编写一个辅助函数str-to-pattern(或任何你想调用的函数),它接受一个字符串,双重转义它需要的所有内容,然后调用re-pattern它。

编辑:制作一个字符串到模式函数
有很多方法可以做到这一点,下面只是一个例子。我首先制作一个正则表达式转义字符映射到他们的字符串替换。“smap”不是实际类型,但从功能上讲,它是一个我们将使用“旧值”与“新值”交换的映射,其中“旧值”是 smap 键的成员,“新值”是 smap 的 val 的对应成员。在我们的例子中,这个 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))
于 2012-07-26T15:14:26.263 回答
3

你确定错误来自读者(即来自clojure本身)吗?

正则表达式使用括​​号,它们也必须在那里匹配。我猜这个错误来自试图编译正则表达式的代码。

如果您想在正则表达式中转义括号,请使用反引号:(def p #"\)!@#$%^&*\(\)")

[更新] 啊,对不起,你可能需要像 Omri 天那样双重转义。

于 2012-07-26T14:53:34.350 回答
3

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)
")!@#$%^&*()"
于 2013-10-10T00:34:50.173 回答