用 Clojure 地图中的一组字符替换字符串中的字符
Replacing characters in a string, with a set of characters inside of a map in Clojure
我有一个接受字符串 s
和字符映射 charmap
的函数。如果字符串 s
中的任何字符在 charmap
内,请将字符替换为映射的值。
注意,映射中的键必须是字符串,而不是字符。
例如:
(replace-characters "Hi!" {"!" "Exclamation Mark"}) ;; => "HiExclamation Mark"
这是我目前使用的代码:
(defn- replace-characters
"Replaces any characters in a string that are mapped in the given charmap"
[s charmap]
(let [character-set (set s)
characters (filter #(contains? charmap (str %)) character-set)]
(string/replace s (re-pattern (string/join "|" characters)) charmap)))
但是,我得到了一个 NullPointerException
,我很困惑为什么。
java.lang.NullPointerException: Cannot invoke "String.indexOf(int)" because "s" is null
我想最好在纯 Clojure 中解决这个问题,而不是 Java,等等
Update: 所以上面的代码在 repl 中有效。这很好。但由于某种原因,以下是导致错误的原因:
(-> s
(string/replace #"[:/?#\[\]@!$&'()*+,;=]" "")
(replace-characters charmap)) ;; Where charmap is a large map of key value characters.
这是导致错误的表达式:
(str/replace "Hi" #"" {"!" "Exclamation Mark"})
("!"
被正则表达式替换为 ""
,character-set
的值为 #{\H \i}
而 characters
为 ()
,因此模式已创建re-pattern
是 #""
。)
空正则表达式匹配字母之间的每个 space:
(str/replace "Hi" #"" " ")
=> " H i "
因此,replace
正在 hash-map {"!" "Exclamation Mark"}
中寻找替代品,但没有找到任何东西 - 没有密钥 ""
:
(str/replace "Hi" #"" {"!" "Exclamation Mark"})
=> error
(str/replace "Hi" #"" {"" " "})
=> " H i "
一种可能的解决方案是简化 replace-characters
的定义(此解决方案仅适用于 non-empty charmap
):
(defn replace-characters [s charmap]
(str/replace s (re-pattern (str/join "|" (keys charmap)))
charmap))
测试:
(replace-characters "Hi!" {"!" "Exclamation Mark"})
=> "HiExclamation Mark"
(-> "Hi!"
(str/replace #"[:/?#\[\]@!$&'()*+,;=]" "")
(replace-characters {"!" "Exclamation Mark"}))
=> "Hi"
我会选择像这样简单的东西:
(apply str (replace {"!" "[exclamation mark]"
"?" "[question mark]"}
(map str "is it possible? sure!")))
;;=> "is it possible[question mark] sure[exclamation mark]"
或者这样使用传感器:
(apply str (eduction (map str) (replace {"!" "[exclamation mark]"
"?" "[question mark]"})
"is it possible? sure!"))
或者像这样:
(defn replace-characters [s rep]
(apply str (map #(rep (str %) %) s)))
user> (replace-characters "is it possible? sure!" {"!" "[exclamation mark]"
"?" "[question mark]"})
;;=> "is it possible[question mark] sure[exclamation mark]"
string/escape
完全按照您的意愿行事:
(string/escape "Hi!" {\! "Exclamation Mark"})
;; => "HiExclamation Mark"
该函数使用从字符到替换的映射来替换字符。
如果你想替换正则表达式或字符串,你可以使用 reduce-kv
in combination with string/replace
:
(def replacements
(array-map
"!" "Exclamation Mark"
#"[:/?#\[\]@!$&'()*+,;=]" ""
#_more_replacements))
(defn replace [s replacements]
(reduce-kv string/replace s replacements))
因此,您循环(按顺序,当 replacements
是 array-map
时)替换的键和值,并使用 [=16= 将它们应用于字符串 s
].
(replace "Hi!" replacements)
;; => "HiExclamation Mark"
如果 array-map
中元素的顺序颠倒,则替换 !使用 ""
(因为 ! 在正则表达式中)会成功:
(replace "Hi!" (into (array-map) (reverse replacements)))
;; => "Hi"
我有一个接受字符串 s
和字符映射 charmap
的函数。如果字符串 s
中的任何字符在 charmap
内,请将字符替换为映射的值。
注意,映射中的键必须是字符串,而不是字符。
例如:
(replace-characters "Hi!" {"!" "Exclamation Mark"}) ;; => "HiExclamation Mark"
这是我目前使用的代码:
(defn- replace-characters
"Replaces any characters in a string that are mapped in the given charmap"
[s charmap]
(let [character-set (set s)
characters (filter #(contains? charmap (str %)) character-set)]
(string/replace s (re-pattern (string/join "|" characters)) charmap)))
但是,我得到了一个 NullPointerException
,我很困惑为什么。
java.lang.NullPointerException: Cannot invoke "String.indexOf(int)" because "s" is null
我想最好在纯 Clojure 中解决这个问题,而不是 Java,等等
Update: 所以上面的代码在 repl 中有效。这很好。但由于某种原因,以下是导致错误的原因:
(-> s
(string/replace #"[:/?#\[\]@!$&'()*+,;=]" "")
(replace-characters charmap)) ;; Where charmap is a large map of key value characters.
这是导致错误的表达式:
(str/replace "Hi" #"" {"!" "Exclamation Mark"})
("!"
被正则表达式替换为 ""
,character-set
的值为 #{\H \i}
而 characters
为 ()
,因此模式已创建re-pattern
是 #""
。)
空正则表达式匹配字母之间的每个 space:
(str/replace "Hi" #"" " ")
=> " H i "
因此,replace
正在 hash-map {"!" "Exclamation Mark"}
中寻找替代品,但没有找到任何东西 - 没有密钥 ""
:
(str/replace "Hi" #"" {"!" "Exclamation Mark"})
=> error
(str/replace "Hi" #"" {"" " "})
=> " H i "
一种可能的解决方案是简化 replace-characters
的定义(此解决方案仅适用于 non-empty charmap
):
(defn replace-characters [s charmap]
(str/replace s (re-pattern (str/join "|" (keys charmap)))
charmap))
测试:
(replace-characters "Hi!" {"!" "Exclamation Mark"})
=> "HiExclamation Mark"
(-> "Hi!"
(str/replace #"[:/?#\[\]@!$&'()*+,;=]" "")
(replace-characters {"!" "Exclamation Mark"}))
=> "Hi"
我会选择像这样简单的东西:
(apply str (replace {"!" "[exclamation mark]"
"?" "[question mark]"}
(map str "is it possible? sure!")))
;;=> "is it possible[question mark] sure[exclamation mark]"
或者这样使用传感器:
(apply str (eduction (map str) (replace {"!" "[exclamation mark]"
"?" "[question mark]"})
"is it possible? sure!"))
或者像这样:
(defn replace-characters [s rep]
(apply str (map #(rep (str %) %) s)))
user> (replace-characters "is it possible? sure!" {"!" "[exclamation mark]"
"?" "[question mark]"})
;;=> "is it possible[question mark] sure[exclamation mark]"
string/escape
完全按照您的意愿行事:
(string/escape "Hi!" {\! "Exclamation Mark"})
;; => "HiExclamation Mark"
该函数使用从字符到替换的映射来替换字符。
如果你想替换正则表达式或字符串,你可以使用 reduce-kv
in combination with string/replace
:
(def replacements
(array-map
"!" "Exclamation Mark"
#"[:/?#\[\]@!$&'()*+,;=]" ""
#_more_replacements))
(defn replace [s replacements]
(reduce-kv string/replace s replacements))
因此,您循环(按顺序,当 replacements
是 array-map
时)替换的键和值,并使用 [=16= 将它们应用于字符串 s
].
(replace "Hi!" replacements)
;; => "HiExclamation Mark"
如果 array-map
中元素的顺序颠倒,则替换 !使用 ""
(因为 ! 在正则表达式中)会成功:
(replace "Hi!" (into (array-map) (reverse replacements)))
;; => "Hi"