(* csv.ml - comma separated values parser
*
- * $Id: csv.ml,v 1.3 2004-12-22 13:47:51 rich Exp $
+ * $Id: csv.ml,v 1.5 2005-02-17 15:51:47 rich Exp $
*)
(* The format of CSV files:
csv
+let square csv =
+ let columns = columns csv in
+ List.map (
+ fun row ->
+ let n = List.length row in
+ let row = List.rev row in
+ let rec loop acc = function
+ | 0 -> acc
+ | i -> "" :: loop acc (i-1)
+ in
+ let row = loop row (columns - n) in
+ List.rev row
+ ) csv
+
let associate header data =
let nr_cols = List.length header in
let rec trunc = function
output_char chan '\n') csv
let print ?separator csv =
- save_out ?separator stdout csv
+ save_out ?separator stdout csv; flush stdout
let save ?separator file csv =
let chan = open_out file in
save_out ?separator chan csv;
close_out chan
+
+let save_out_readable chan csv =
+ (* Escape all the strings in the CSV file first. *)
+ let csv = List.map (List.map String.escaped) csv in
+
+ let csv = square csv in
+
+ (* Find the width of each column. *)
+ let widths =
+ match csv with
+ | [] -> []
+ | r :: _ ->
+ let n = List.length r in
+ let lengths = List.map (List.map String.length) csv in
+ let max2rows r1 r2 =
+ let rp = List.combine r1 r2 in
+ List.map (fun ((a : int), (b : int)) -> max a b) rp
+ in
+ let rec repeat x = function
+ | 0 -> []
+ | i -> x :: repeat x (i-1)
+ in
+ List.fold_left max2rows (repeat 0 n) lengths in
+
+ (* Print out each cell at the correct width. *)
+ let rec repeat f = function
+ | 0 -> ()
+ | i -> f (); repeat f (i-1)
+ in
+ List.iter (
+ fun row ->
+ let row = List.combine widths row in
+ List.iter (
+ fun (width, cell) ->
+ output_string chan cell;
+ let n = String.length cell in
+ repeat (fun () -> output_char chan ' ') (width - n + 1)
+ ) row;
+ output_char chan '\n'
+ ) csv
+
+let print_readable = save_out_readable stdout