在克洛朱尔的地图给出了意想不到的结果



在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)

最新更新