Align columns: Difference between revisions
Content added Content deleted
(→version 3: Note: This version adds boxes around columns of output.) |
(→{{header|Clojure}}: replaced code with shorter version) |
||
Line 366: | Line 366: | ||
=={{header|Clojure}}== |
=={{header|Clojure}}== |
||
<lang Clojure> |
<lang Clojure> |
||
⚫ | |||
(:require [clojure.contrib.string :as str])) |
|||
(def data "Given$a$text$file$of$many$lines,$where$fields$within$a$line$ |
|||
; Returns the list of words between $ characters in string. |
|||
are$delineated$by$a$single$'dollar'$character,$write$a$program |
|||
(defn split [string] |
|||
that$aligns$each$column$of$fields$by$ensuring$that$words$in$each$ |
|||
(let [[before after] (split-with (partial not= \$) string)] |
|||
column$are$separated$by$at$least$one$space. |
|||
(if (empty? after) |
|||
Further,$allow$for$each$word$in$a$column$to$be$either$left$ |
|||
`(~(apply str before)) |
|||
justified,$right$justified,$or$center$justified$within$its$column.") |
|||
(cons (apply str before) (split (rest after)))))) |
|||
(def table (map #(str/split #"\$" %) (str/split-lines data))) |
|||
(defn find-widths [lst-of-lines] |
|||
(let [all-widths (map (fn [line] (map count line)) lst-of-lines)] |
|||
(let [field-count (apply max (map count all-widths))] |
|||
(let [all-widths (map #(take field-count (concat % (repeat 0))) all-widths)] |
|||
(apply map max all-widths))))) |
|||
(defn col-width [n table] (reduce max (map #(try (count (nth % n)) |
|||
(defn pad [lst-of-lst filler] |
|||
(catch Exception _ 0)) |
|||
(let [max-size (apply max (map count lst-of-lst))] |
|||
table))) |
|||
(map #(take max-size (concat % (repeat filler))) lst-of-lst))) |
|||
⚫ | |||
(defn add-padding |
|||
"if the string is too big turncate it, else return a string with padding" |
|||
[string width justification] |
|||
(if (>= (count string) width) (str/take width string) |
|||
(let [pad-len (int (- width (count string))) ;we don't want rationals |
|||
half-pad-len (int (/ pad-len 2))] |
|||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
(defn |
(defn aligned-table |
||
"get the width of each column, then generate a new table with propper padding for eath item" |
|||
(map split (line-seq in-stream))) |
|||
([table justification] |
|||
(let [col-widths (map #(+ 2 (col-width % table)) (range (count(first table))))] |
|||
(map |
|||
(fn [row] (map #(add-padding %1 %2 justification) row col-widths)) |
|||
table)))) |
|||
(defn |
(defn print-table |
||
[table] |
|||
[(quot x 2) (+ (mod x 2) (quot x 2))]) |
|||
(do (println) |
|||
(print (str/join "" (flatten (interleave table (repeat "\n"))))))) |
|||
(defn spaces [cnt] |
|||
⚫ | |||
(defn do-print [just widths line] |
|||
(if (empty? widths) |
|||
(newline) |
|||
(let [wid (first widths) wrd (first line)] |
|||
(let [diff (- wid (count wrd))] |
|||
⚫ | |||
⚫ | |||
⚫ | |||
:centre (let [[lhs rhs] (half diff)] |
|||
⚫ | |||
(throw (IllegalArgumentException.))) |
|||
(recur just (rest widths) (rest line)))))) |
|||
⚫ | |||
; Default is left-justified alignment of standard input |
|||
([] (align-columns :left *in*)) |
|||
([just] (align-columns just *in*)) |
|||
([just in-stream] |
|||
(let [data (read-all in-stream)] |
|||
(let [widths (find-widths data) data (pad data "")] |
|||
(doseq [line data] (do-print just widths line)))))) |
|||
(print-table (aligned-table table :center)) |
|||
</lang> |
</lang> |
||