在clojure中使用map,检查字符串是否包含大写字符。
(map #(= (clojure.string/upper-case %) %) "Hello")
预期结果。
(true false false false false)
不幸的是,结果出乎意料。
(false false false false false)
当我在第一个"%"中替换"H"时,我做了一个实验,结果仍然出乎意料。
(map #(= (clojure.string/upper-case "H") %) "Hello")
(false false false false false)
当我在第二个"%"中替换"H"时,结果发生了变化,这是预期的结果。
(map #(= (clojure.string/upper-case %) "H) "Hello")
(true false false false false)
这是怎么回事?请随时发表评论。
正如其他人指出的那样,将字符与字符串进行比较是行不通的。比较字符串将起作用:
(map #(= (clojure.string/upper-case %) (str %)) "Hello")
=> (true false false false false)
但是,这更直接:
(map #(Character/isUpperCase %) "Hello")
=> (true false false false false)
这是因为您错误地认为map
将字符串"Hello"
分解为("H" "e" "l" "l" "o")
但事实并非如此!
尝试:
(map identity "Hello") ;; => (H e l l o)
因此,map 将字符串剖析为字符列表,而不是单个字符串列表。
所以你的(map #(= (clojure.string/upper-case %) %) "Hello")
正在比较(clojure.string/upper-case H)
导致H
"H"
。 由于一个是单个字符串,另一个是字符,因此结果是false
- 由于类型差异。
(map #(= (clojure.string/upper-case %) (str %)) "Hello")
但是,它符合您对原始代码的期望。 它返回:
(true false false false false)
功能
最有效的方法可能是使用正则表达式:
(defn has-upper-case? [s] (boolean (re-find #"[A-Z]" s)))
不太严格(没有布尔值返回,但字符串的第一个上部单个字符串从左到右或nil
(如果未找到):
(defn has-upper-case? [s] (re-find #"[A-Z]" s))
您无法将字符串与字符进行比较。 由字符串组成的序列是字符列表。
(seq "Hello")
;; => (H e l l o)
(map class "Hello")
;; => (java.lang.Character java.lang.Character java.lang.Character java.lang.Character java.lang.Character)
因此,在您的情况下,您的测试归结为
(= "H" H) ;; => false
这是错误的。
要使其正常工作,请尝试以下操作之一:
;; compare strings
(map #(= (clojure.string/upper-case %) (str %)) "Hello")
;; => (true false false false false)
;; compare chars
(map #(= (first (clojure.string/upper-case %)) %) "Hello")
;; => (true false false false false)
upper-case
将字符串转换为全部大写。
参考: https://clojuredocs.org/clojure.string/upper-case
你需要使用这样的东西:
(some #(Character/isUpperCase %) "Hello") => true
(some #(Character/isUpperCase %) "hello") => nil
你被clojure.string/upper-case
的未记录行为所吸引:
- 它适用于任何对象,而不仅仅是字符串。
- 它始终返回一个字符串。
所以,例如,
(clojure.string/upper-case +)
=> "CLOJURE.CORE$_PLUS_@19CFE007"
如果您查看源代码,您会发现它在.toUpperCase
之前.toString
应用。
所以它也适用于单个字符。但它返回一个字符串,而不是 - 我期望的 - 一个字符:
(clojure.string/upper-case 1)
=> "1"
补救措施是将upper-case
应用于整个字符串,然后将map
与=
一起使用,逐个字符将原始字符串与转换后的字符串进行比较:
(#(map = (clojure.string/upper-case %) %) "Hello")
=> (true false false false false)
或者,使用(fn [...] ...)
而不是#(...)
,
((fn [coll] (map = (clojure.string/upper-case coll) coll)) "Hello")
=> (true false false false false)