Asking Bob a question?
(= \? (last "this is a question?"))
(= \? (last "this is still a question? "))
clojure.string/trimr will remove all the trailing whitespace from the right side of a string. Once trimmed, then our initial comparison code will work again.
(= \? (last (clojure.string/trimr "this is still a question? ")))
Shouting at Bob
Unfortunately the clojure.string API does not have a function to check if a string is in capital letters. There is an
upper-case function, so a comparison can be made with the original string and the string returned from
(clojure.string/upper-case "watch out!")
(= "WATCH OUT!" (clojure.string/upper-case "WATCH OUT!"))
(= "watch out!" (clojure.string/upper-case "watch out!"))
(= "1, 2, 3" (clojure.string/upper-case "1, 2, 3"))
To support all Unicode characters there is an isLetter method that takes an integer type. As there could be any kind of characters in the phrase, we will use the int version. This required conversing the character to an int first before calling
(Character/isLetter (int \a))
some function is used to iterate over all the characters in the phrase. As soon as a letter is found it returns true, so does not need to process the whole phrase unless no letter is found.
(some #(Character/isLetter (int %)) phrase)
Silence of the Bob
(defn response-for [phrase] (let [phrase (string/trimr phrase) silence? (string/blank? phrase) question? (= \? (last phrase)) letters? (some #(Character/isLetter (int %)) phrase) shouting? (and (= phrase (string/upper-case phrase)) letters?)] (cond (and shouting? question?) "Calm down, I know what I'm doing!" silence? "Fine. Be that way!" shouting? "Whoa, chill out!" question? "Sure." :else "Whatever.")))
The first let binding,
phraseover-rides the name of the argument to the function. This is not that common an approach as over-riding can lead to confusion. However, in this relatively simple example it feels okay to do. The over-ride is the first let binding and it is preparing the string for all the other let bindings to use.