Pure Danger Tech


Centering a string in Clojure

24 Oct 2010

In service of some other code I was writing, I ran across the need for a function to center a string within a space-padded length. My solution works and I think is easy to read, but I suspect you can do far better (so please share). My solution does not handle or check for a string smaller than the requested padded length.

(defn repeat-str
  "Create a string that repeats s n times."
  [s n]
  (apply str (repeat n s)))

(defn spaces
  "Create a string of n spaces."
  (repeat-str \space n))

(defn center
  "Center s in padding to final size len"
  [s len]
  (let [slen (count s)
        lpad (int (/ (- len slen) 2))
        rpad (- len slen lpad)]
    (str (spaces lpad) s (spaces rpad))))

I needed repeat-str nearby for something other than spaces, so there is value for me in breaking those apart.

I also had fun writing some tests with clojure.test:

(deftest test-center
  ;; test cases where pad length < string length
  (let [s "abc"]
    (doall (map #(is (= s (center s %1)))
                (range (count s)))))

  ;; given a seed string test expected results from padding
  ;;   from length of string to as many expected results given
  (are [s expected-vals]
         #(is (= %2 (center s (+ (count s) %1)))) 

       "" ["" " " "  "]
       "a" ["a" "a " " a " " a  "]
       "ab" ["ab" "ab " " ab " " ab  "]
       "abc" ["abc" "abc " " abc "]))

How can I make these better?