如果我有这套
(def my-set #{"foo.clj" "bar.clj" "baz.clj"})
如何将其转换为此模式字符串:
"foo\.clj|bar\.clj|baz\.clj"
我的尝试:
(defn set->pattern-str [coll]
(-> (clojure.string/join "|" coll)
(clojure.string/replace #"\." "\\\\.")))
(set->pattern-str my-set)
=> "foo\\.clj|baz\\.clj|bar\\.clj" ;I get the double backslash
更好的想法?
答案 0 :(得分:3)
如果您的字符串集合中可能包含其他元字符而不仅仅是.
,则更常规的方法是ask the underlying java.util.regex.Pattern
implementation to escape everything for us:
(import 'java.util.regex.Pattern)
(defn set->pattern-str [coll]
(->> coll
(map #(Pattern/quote %))
(clojure.string/join \|)
re-pattern))
IDEone link here。请记住,IDEone不是REPL,你必须告诉它将值放在stdout上,例如println
之后才能看到它们。
答案 1 :(得分:2)
您接近最终解决方案。显示双反斜杠,因为它显示为已转义。当您将其变为seq
时,您将看到单个字符:
(seq "foo\\.clj")
;;=> (\f \o \o \\ \. \c \l \j)
工作解决方案:
(def my-set #{"foo.clj" "bar.clj" "baz.clj"})
(def my-set-pattern
(-> (clojure.string/join "|" my-set)
(clojure.string/replace "." "\\.")
(re-pattern)))
(re-matches my-set-pattern "foo.clj")
;;=> "foo.clj"
(re-matches my-set-pattern "bar.clj")
;;=> "bar.clj"
(re-matches my-set-pattern "baz.clj")
;;=> "baz.clj"
(re-matches my-set-pattern "foo-clj")
;;=> nil
答案 2 :(得分:0)
编辑:好的,这个确实有效。可能想要将它分开一点,如果它意味着长寿代码,但这是我能找到的最简单的方法,用最少的字符串重写。
(defn is-matching-file-name [target-string]
(re-matches
(re-pattern (clojure.string/escape (String/join "|" my-set) {\. "\\."}))
target-string))
clojure.string / escape在这里有两个参数:要转义的字符串,以及要转义到替换字符串的字符的映射。这个映射中的键是文字\.
,并且值需要两个反斜杠,因为我们希望在最终字符串中包含任意.
之前的一个反斜杠,以用作重新模式函数的参数。