+val trim : ?top:bool -> ?left:bool -> ?right:bool -> ?bottom:bool -> t -> t
+(** This takes a CSV file and trims empty cells.
+ *
+ * All four of the option arguments ([~top], [~left], [~right], [~bottom])
+ * default to [true].
+ *
+ * The exact behaviour is:
+ *
+ * [~right]: If true, remove any empty cells at the right hand end of
+ * any row. The number of columns in the resulting CSV structure will
+ * not necessarily be the same for each row.
+ *
+ * [~top]: If true, remove any empty rows (no cells, or containing just empty
+ * cells) from the top of the CSV structure.
+ *
+ * [~bottom]: If true, remove any empty rows from the bottom of the
+ * CSV structure.
+ *
+ * [~left]: If true, remove any empty columns from the left of the
+ * CSV structure. Note that [~left] and [~right] are quite different:
+ * [~left] considers the whole CSV structure, whereas [~right] considers
+ * each row in isolation.
+ *)
+
+val square : t -> t
+(** Make the CSV data "square" (actually rectangular). This pads out
+ * each row with empty cells so that all rows are the same length as
+ * the longest row. After this operation, every row will have length
+ * {!Csv.columns}.
+ *)
+
+val is_square : t -> bool
+(** Return true iff the CSV is "square" (actually rectangular). This
+ * means that each row has the same number of cells.
+ *)
+
+val set_columns : int -> t -> t
+(** [set_columns cols csv] makes the CSV data square by forcing the width
+ * to the given number of [cols]. Any short rows are padded with blank
+ * cells. Any long rows are truncated.
+ *)
+
+val set_rows : int -> t -> t
+(** [set_rows rows csv] makes the CSV data have exactly [rows] rows
+ * by adding empty rows or truncating rows as necessary.
+ *
+ * Note that [set_rows] does not make the CSV square. If you want it
+ * to be square, call either {!Csv.square} or {!Csv.set_columns} after.
+ *)
+
+val set_size : int -> int -> t -> t
+(** [set_size rows cols csv] makes the CSV data square by forcing the
+ * size to [rows * cols], adding blank cells or truncating as necessary.
+ * It is the same as calling [set_columns cols (set_rows rows csv)]
+ *)
+
+val sub : int -> int -> int -> int -> t -> t
+(** [sub r c rows cols csv] returns a subset of [csv]. The subset is
+ * defined as having top left corner at row [r], column [c] (counting
+ * from [0]) and being [rows] deep and [cols] wide.
+ *
+ * The returned CSV will be square.
+ *)
+
+val to_array : t -> string array array
+val of_array : string array array -> t
+(** Convenience functions to convert to and from a matrix representation.
+ * [to_array] will produce a ragged matrix (not all rows will have the
+ * same length) unless you call {!Csv.square} first.
+ *)
+
+val associate : string list -> t -> (string * string) list list
+(** [associate header data] takes a block of data and converts each
+ * row in turn into an assoc list which maps column header to data cell.
+ *
+ * Typically a spreadsheet will have the format:
+ * {v
+ * header1 header2 header3
+ * data11 data12 data13
+ * data21 data22 data23
+ * ...
+ * v}
+ *
+ * This function arranges the data into a more usable form which is
+ * robust against changes in column ordering. The output of the
+ * function is:
+ * {v
+ * [ ["header1", "data11"; "header2", "data12"; "header3", "data13"];
+ * ["header1", "data21"; "header2", "data22"; "header3", "data23"];
+ * etc. ]
+ * v}
+ *
+ * Each row is turned into an assoc list (see [List.assoc]).
+ *
+ * If a row is too short, it is padded with empty cells ([""]). If
+ * a row is too long, it is truncated.
+ *
+ * You would typically call this function as:
+ *
+ * {v
+ * let header, data = match csv with h :: d -> h, d | [] -> assert false;;
+ * let data = Csv.associate header data;;
+ * v}
+ *
+ * The header strings are shared, so the actual space in memory consumed
+ * by the spreadsheet is not much larger.
+ *)
+
+val print : ?separator:char -> t -> unit