This is a problem from Exercism here, the goal is to clean up badly formatted phone numbers. The rules are:
- If the phone number is less than 10 digits assume that it is a bad number
- If the phone number is 10 digits assume that it is good
- If the phone number is 11 digits and the first number is 1, trim the 1 and use the first 10 digits
- If the phone number is 11 digits and the first number is not 1, then it is a bad number
- If the phone number is more than 11 digits assume that it is a bad number
A function should pretty-print the numbers in the form (123) 456-7890.
Here is my solution. I'm very new to Clojure and am sure it's not idiomatic in parts. For example, should I have stored the different parts of the number as separate variables?
I would also be interested in tips on how to format the code to make it easier to read, I'm only aware of lispy-multiline which I find a bit too aggressive.
All feedback much appreciated.
(ns phone-number)
(defn digit-not-one-or-zero [digit]
(and (not (= \0 digit))
(not (= \1 digit))))
(defn clean-number [num-string]
;; strip all non-digit characters from a string
(filter #(Character/isDigit %) num-string))
(defn check-valid [num-string]
;; number is valid only if:
;; a) length is between 10-11 chars
;; b) if 11 chars, first digit must be 1
;; c) (after stripping first digit if 11), first and fourth can't be 0 or 1
(let [clean-string (clean-number num-string)
len (count clean-string)]
(if (or (< len 10) (> len 11))
false
(if (= len 11)
(if (= \1 (first clean-string))
(check-valid (rest clean-string))
false)
(if (and (digit-not-one-or-zero (first clean-string))
(digit-not-one-or-zero (nth clean-string 3)))
true
false)))))
(defn number [num-string]
(if (check-valid num-string)
(let [clean-string (clean-number num-string)]
(if (= (count clean-string) 10)
(apply str (clean-number clean-string)) (apply str (rest (clean-number clean-string)))))
"0000000000"))
(defn area-code [num-string]
;; get the first 3 chars of the cleaned up number
(apply str (take 3 (number num-string))))
(defn pretty-print [num-string]
(let [formatted-number (number num-string)]
(apply str (concat
"(" (area-code num-string) ")" " " (subs formatted-number 3 6) "-" (subs formatted-number 6)))))