Align columns

From Rosetta Code
Task
Align columns
You are encouraged to solve this task according to the task description, using any language you may know.

Given a text file of many lines, where fields within a line are delineated by a single 'dollar' character, write a program that aligns each column of fields by ensuring that words in each column are separated by at least one space. Further, allow for each word in a column to be either left justified, right justified, or center justified within its column.


Use the following text to test your programs:

Given$a$text$file$of$many$lines,$where$fields$within$a$line$
are$delineated$by$a$single$'dollar'$character,$write$a$program
that$aligns$each$column$of$fields$by$ensuring$that$words$in$each$
column$are$separated$by$at$least$one$space.
Further,$allow$for$each$word$in$a$column$to$be$either$left$
justified,$right$justified,$or$center$justified$within$its$column.

Note that:

  1. The example input texts lines may, or may not, have trailing dollar characters.
  2. All columns should share the same alignment.
  3. Consecutive space characters produced adjacent to the end of lines are insignificant for the purposes of the task.
  4. Output text will be viewed in a mono-spaced font.

ABAP

<lang ABAP>report z_align no standard page header. start-of-selection.

data: lt_strings type standard table of string,

     lv_strings type string.

append: 'Given$a$text$file$of$many$lines,$where$fields$within$a$line$' to lt_strings,

       'are$delineated$by$a$single$dollar$character,$write$a$program' to lt_strings,
       'that$aligns$each$column$of$fields$by$ensuring$that$words$in$each$' to lt_strings,
       'column$are$separated$by$at$least$one$space.' to lt_strings,
       'Further,$allow$for$each$word$in$a$column$to$be$either$left$' to lt_strings,
       'justified,$right$justified,$or$center$justified$within$its$column.' to lt_strings.

types ty_strings type standard table of string.

perform align_col using 'LEFT' lt_strings. skip. perform align_col using 'RIGHT' lt_strings. skip. perform align_col using 'CENTER' lt_strings.


form align_col using iv_just type string iv_strings type ty_strings.

 constants: c_del value '$'.
 data: lv_string type string,
       lt_strings type table of string,
       lt_tables like table of lt_strings,
       lv_first type string,
       lv_second type string,
       lv_longest type i value 0,
       lv_off type i value 0,
       lv_len type i.
 " Loop through the supplied text. It is expected at the input is a table of strings, with each
 " entry in the table representing a new line of the input.
 loop at iv_strings into lv_string.
   " Split the current line at the delimiter.
   split lv_string at c_del into lv_first lv_second.
   " Loop through the line splitting at every delimiter.
   do.
     append lv_first to lt_strings.
     lv_len = strlen( lv_first ).
     " Check if the length of the new string is greater than the currently stored length.
     if lv_len > lv_longest.
       lv_longest = lv_len.
     endif.
     if lv_second na c_del.
       " Check if the string is longer than the recorded maximum.
       lv_len = strlen( lv_second ).
       if lv_len > lv_longest.
         lv_longest = lv_len.
       endif.
       append lv_second to lt_strings.
       exit.
     endif.
     split lv_second at c_del into lv_first lv_second.
   enddo.
   append lt_strings to lt_tables.
   clear lt_strings.
 endloop.
 " Loop through each line of input.
 loop at lt_tables into lt_strings.
   " Loop through each word in the line (Separated by specified delimiter).
   loop at lt_strings into lv_string.
     lv_off = ( sy-tabix - 1 ) * ( lv_longest + 2 ).
     case iv_just.
       when 'LEFT'.
         write : at (lv_longest) lv_string left-justified.
       when 'RIGHT'.
         write at (lv_longest) lv_string right-justified.
       when 'CENTER'.
         write at (lv_longest) lv_string centered.
     endcase.
   endloop.
   skip.
   sy-linno = sy-linno - 1.
 endloop.

endform.</lang>

Given      a          text       file       of         many       lines,     where      fields     within     a          line
are        delineated by         a          single     'dollar'   character, write      a          program
that       aligns     each       column     of         fields     by         ensuring   that       words      in         each
column     are        separated  by         at         least      one        space.
Further,   allow      for        each       word       in         a          column     to         be         either     left
justified, right      justified, or         center     justified  within     its        column.

     Given          a       text       file         of       many     lines,      where     fields     within          a       line
       are delineated         by          a     single   'dollar' character,      write          a    program
      that     aligns       each     column         of     fields         by   ensuring       that      words         in       each
    column        are  separated         by         at      least        one     space.
  Further,      allow        for       each       word         in          a     column         to         be     either       left
justified,      right justified,         or     center  justified     within        its    column.

  Given        a         text       file        of        many      lines,     where      fields     within       a         line
   are     delineated     by         a        single    'dollar'  character,   write        a       program
   that      aligns      each      column       of       fields       by      ensuring     that      words        in        each
  column      are     separated      by         at       least       one       space.
 Further,    allow       for        each       word        in         a        column       to         be       either      left
justified,   right    justified,     or       center   justified    within      its      column.

Ada

<lang ada>with Ada.Characters.Latin_1; use Ada.Characters.Latin_1; with Ada.Text_IO; use Ada.Text_IO; with Strings_Edit; use Strings_Edit;

procedure Column_Aligner is

  Text : constant String :=
     "Given$a$text$file$of$many$lines,$where$fields$within$a$line$" & NUL &
     "are$delineated$by$a$single$'dollar'$character,$write$a$program" & NUL &
     "that$aligns$each$column$of$fields$by$ensuring$that$words$in$each$" & NUL &
     "column$are$separated$by$at$least$one$space." & NUL &
     "Further,$allow$for$each$word$in$a$column$to$be$either$left$" & NUL &
     "justified,$right$justified,$or$center$justified$within$its$column." & NUL;
  File    : File_Type;
  Width   : array (1..1_000) of Natural := (others => 0);
  Line    : String (1..200);
  Column  : Positive := 1;
  Start   : Positive := 1;
  Pointer : Positive;

begin

  Create (File, Out_File, "columned.txt");
     -- Determining the widths of columns
  for I in Text'Range loop
     case Text (I) is
        when '$' | NUL =>
           Width (Column) := Natural'Max (Width (Column), I - Start + 1);
           Start  := I + 1;
           if Text (I) = NUL then
              Column := 1;
           else
              Column := Column + 1;
           end if;
        when others =>
           null;
     end case;
  end loop;
     -- Formatting
  for Align in Alignment loop
     Column  := 1;
     Start   := 1;
     Pointer := 1;
     for I in Text'Range loop
        case Text (I) is
           when '$' | NUL =>
              Put -- Formatted output of a word
              (  Destination => Line,
                 Pointer     => Pointer,
                 Value       => Text (Start..I - 1),
                 Field       => Width (Column),
                 Justify     => Align
              );
              Start  := I + 1;
              if Text (I) = NUL then
                 Put_Line (File, Line (1..Pointer - 1));
                 Pointer := 1;
                 Column := 1;
              else
                 Column := Column + 1;
              end if;
           when others =>
              null;
        end case;
     end loop;
  end loop;
  Close (File);

end Column_Aligner;</lang> Formatted file sample:

Given      a          text       file   of     many      lines,     where    fields  within  a      line  
are        delineated by         a      single 'dollar'  character, write    a       program 
that       aligns     each       column of     fields    by         ensuring that    words   in     each  
column     are        separated  by     at     least     one        space.   
Further,   allow      for        each   word   in        a          column   to      be      either left  
justified, right      justified, or     center justified within     its      column. 
      Given          a       text   file     of      many     lines,    where  fields  within      a line 
        are delineated         by      a single  'dollar' character,    write       a program
       that     aligns       each column     of    fields         by ensuring    that   words     in each 
     column        are  separated     by     at     least        one   space.
   Further,      allow        for   each   word        in          a   column      to      be either left 
 justified,      right justified,     or center justified     within      its column.
   Given        a        text     file    of      many     lines,     where   fields  within    a   line  
    are    delineated     by        a   single  'dollar' character,   write     a    program 
   that      aligns      each    column   of     fields      by     ensuring   that   words    in   each  
  column       are     separated   by     at     least       one     space.  
 Further,     allow       for     each   word      in         a      column     to      be   either left  
justified,    right   justified,   or   center justified   within      its   column. 

ALGOL 68

<lang algol68>STRING nl = REPR 10; STRING text in list := "Given$a$text$file$of$many$lines,$where$fields$within$a$line$"+nl+

 "are$delineated$by$a$single$'dollar'$character,$write$a$program"+nl+
 "that$aligns$each$column$of$fields$by$ensuring$that$words$in$each$"+nl+
 "column$are$separated$by$at$least$one$space."+nl+
 "Further,$allow$for$each$word$in$a$column$to$be$either$left$"+nl+
 "justified,$right$justified,$or$center$justified$within$its$column.";

MODE PAGE = FLEX[0,0]STRING; PAGE page;

PROC flex page = (PAGE in page, INT row, col)PAGE:(

 HEAP FLEX[row, col]STRING out page;
 out page[:1 UPB in page, :2 UPB in page] := in page;
 FOR r TO row DO
   FOR c FROM 2 UPB in page + 1 TO col DO out page[r,c]:="" OD
 OD;
 FOR r FROM 1 UPB in page + 1 TO row DO
   FOR c FROM 1 TO col DO out page[r,c]:="" OD
 OD;
 out page

);

FILE text in file; associate(text in file, text in list); make term(text in file, "$");

on physical file end(text in file, (REF FILE skip)BOOL: stop iteration); on logical file end(text in file, (REF FILE skip)BOOL: stop iteration); FOR row DO

 on line end(text in file, (REF FILE skip)BOOL: stop iteration);
 FOR col DO
   STRING tok;
   getf(text in file, ($gx$,tok));
   IF row > 1 UPB page THEN page := flex page(page, row, 2 UPB page) FI; 
   IF col > 2 UPB page THEN page := flex page(page, 1 UPB page, col) FI; 
   page[row,col]:=tok
 OD;
 stop iteration: 
   SKIP

OD; stop iteration:

 SKIP;

BEGIN

 PROC aligner = (PAGE in page, PROC (STRING,INT)STRING aligner)VOID:(
   PAGE page := in page;
   [2 UPB page]INT max width;
   FOR col TO 2 UPB page DO
     INT max len:=0; FOR row TO UPB page DO IF UPB page[row,col]>max len THEN max len:=UPB page[row,col] FI OD;
     FOR row TO UPB page DO page[row,col] := aligner(page[row,col], maxlen) OD
   OD;
   printf(($n(UPB page)(n(2 UPB page -1)(gx)gl)$,page))
 );
 PROC left = (STRING in, INT len)STRING: in + " "*(len - UPB in),
      right = (STRING in, INT len)STRING: " "*(len - UPB in) + in,
      centre = (STRING in, INT len)STRING: ( INT pad=len-UPB in;  pad%2*" "+ in + (pad-pad%2)*" " );
 
 []STRUCT(STRING name, PROC(STRING,INT)STRING align) aligners = (("Left",left), ("Left",right), ("Centre",centre));
 
 FOR index TO UPB aligners DO 
   print((new line, "# ",name OF aligners[index]," Column-aligned output:",new line));
   aligner(page, align OF aligners[index]) 
 OD

END</lang>

AutoHotkey

<lang AutoHotkey>lines = ( |$|$|$|$|$|$|$|$|$|$|$| Given$a$text$file$of$many$lines,$where$fields$within$a$line$ are$delineated$by$a$single$'dollar'$character,$write$a$program that$aligns$each$column$of$fields$by$ensuring$that$words$in$each$ column$are$separated$by$at$least$one$space. Further,$allow$for$each$word$in$a$column$to$be$either$left$ justified,$right$justified,$or$center$justified$within$its$column. )

Clipboard := ColumnJustify(lines, "l")

MsgBox, , Column Justify, The clipboard now contains the justified text. Paste it into a text editor to see it.

ColumnJustify(lines, lcr = "l", del="$") {

 Loop, Parse, lines, `n, `r
   Loop, Parse, A_LoopField, %del%
   {
     If ((t := StrLen(A_LoopField)) > c%A_Index% )
       c%A_Index% :=  t
     If (t > max)
       max := t
   }
 blank := Fill( " ", max )
 If (lcr = "l") ;left-justify
   Loop, Parse, lines, `n, `r
     Loop, Parse, A_LoopField, %del%
       out .= (A_Index = 1 ? "`n" : " ") SubStr(A_LoopField blank, 1, c%A_Index%)
 Else If (lcr = "r") ;right-justify
   Loop, Parse, lines, `n, `r
     Loop, Parse, A_LoopField, %del%
       out .= (A_Index = 1 ? "`n" : " ") SubStr(blank A_LoopField, -c%A_Index%+1)
 Else If (lcr = "c") ;center-justify
   Loop, Parse, lines, `n, `r
     Loop, Parse, A_LoopField, %del%
       out .= (A_Index = 1 ? "`n" : " ") SubStr(blank A_LoopField blank
         , (Ceil((max * 2 + StrLen(A_LoopField))/2) - Ceil(c%A_Index%/2) + 1)
         , c%A_Index%)
 return SubStr(out, 2)

}

Fill(chr, len) {

 static y
 if !y
   VarSetCapacity(x, 64), VarSetCapacity(x, 0), y := True
 return x, VarSetCapacity(x, len, Asc(chr))

}</lang>

AWK

<lang awk>BEGIN {

 FS="$"
 lcounter = 1
 maxfield = 0
 # justistification; pick up one
 #justify = "left"
 justify = "center"
 #justify = "right"

} {

 if ( NF > maxfield ) maxfield = NF;
 for(i=1; i <= NF; i++) {
   line[lcounter,i] = $i
   if ( longest[i] == "" ) longest[i] = 0;
   if ( length($i) > longest[i] ) longest[i] = length($i);
 }
 lcounter++

} END {

 just = (justify == "left") ? "-" : ""
 for(i=1; i <= NR; i++) {
   for(j=1; j <= maxfield; j++) {
     if ( justify != "center" ) {

template = "%" just longest[j] "s "

     } else {

v = int((longest[j] - length(line[i,j]))/2) rt = "%" v+1 "s%%-%ds" template = sprintf(rt, "", longest[j] - v)

     }
     printf(template, line[i,j])
   }
   print ""
 }

}</lang>

BBC BASIC

<lang bbcbasic> DATA 6

     DATA "Given$a$text$file$of$many$lines,$where$fields$within$a$line$"
     DATA "are$delineated$by$a$single$'dollar'$character,$write$a$program"
     DATA "that$aligns$each$column$of$fields$by$ensuring$that$words$in$each$"
     DATA "column$are$separated$by$at$least$one$space."
     DATA "Further,$allow$for$each$word$in$a$column$to$be$either$left$"
     DATA "justified,$right$justified,$or$center$justified$within$its$column."
     
     REM First find the maximum length of a 'word':
     max% = 0
     READ nlines%
     FOR Line% = 1 TO nlines%
       READ text$
       REPEAT
         word$ = FNword(text$, "$")
         IF LEN(word$) > max% THEN max% = LEN(word$)
       UNTIL word$ = ""
     NEXT Line%
     @% = max% : REM set column width
     
     REM Now display the aligned text:
     RESTORE
     READ nlines%
     FOR Line% = 1 TO nlines%
       READ text$
       REPEAT
         word$ = FNword(text$, "$")
         PRINT FNjustify(word$, max%, "left"),;
       UNTIL word$ = ""
       PRINT
     NEXT Line%
     
     END
     
     DEF FNword(text$, delim$)
     PRIVATE delim%
     LOCAL previous%
     IF delim% = 0 THEN
       previous% = 1
     ELSE
       previous% = delim% + LEN(delim$)
     ENDIF
     delim% = INSTR(text$+delim$, delim$, previous%)
     IF delim% = 0 THEN
       = ""
     ELSE
       = MID$(text$, previous%, delim%-previous%) + " "
     ENDIF
     
     DEF FNjustify(word$, field%, mode$)
     IF word$ = "" THEN = ""
     CASE mode$ OF
       WHEN "center": = STRING$((field%-LEN(word$)) DIV 2, " ") + word$
       WHEN "right": = STRING$(field%-LEN(word$), " ") + word$
     ENDCASE
     = word$</lang>

C

See Column Aligner/C

C++

See Column Aligner/C++

C#

Uses a delegate, which were added to the language in C# 2, to define left-, right-, or center-justified.

Works with: C# version 2+

<lang csharp>using System; class ColumnAlignerProgram {

   delegate string Justification(string s, int width);
   static string[] AlignColumns(string[] lines, Justification justification)
   {
       const char Separator = '$';
       // build input table and calculate columns count
       string[][] table = new string[lines.Length][];
       int columns = 0;
       for (int i = 0; i < lines.Length; i++)
       {
           string[] row = lines[i].TrimEnd(Separator).Split(Separator);
           if (columns < row.Length) columns = row.Length;
           table[i] = row;
       }
       // create formatted table
       string[][] formattedTable = new string[table.Length][];
       for (int i = 0; i < formattedTable.Length; i++)
       {
           formattedTable[i] = new string[columns];
       }
       for (int j = 0; j < columns; j++)
       {
           // get max column width
           int columnWidth = 0;
           for (int i = 0; i < table.Length; i++)
           {
               if (j < table[i].Length && columnWidth < table[i][j].Length)
                   columnWidth = table[i][j].Length;
           }
           // justify column cells
           for (int i = 0; i < formattedTable.Length; i++)
           {
               if (j < table[i].Length)
                   formattedTable[i][j] = justification(table[i][j], columnWidth);
               else 
                   formattedTable[i][j] = new String(' ', columnWidth);
           }
       }
       // create result
       string[] result = new string[formattedTable.Length];
       for (int i = 0; i < result.Length; i++)
       {
           result[i] = String.Join(" ", formattedTable[i]);
       }
       return result;
   }
   static string JustifyLeft(string s, int width) { return s.PadRight(width); }
   static string JustifyRight(string s, int width) { return s.PadLeft(width); }
   static string JustifyCenter(string s, int width) 
   { 
       return s.PadLeft((width + s.Length) / 2).PadRight(width); 
   }
   static void Main()
   {
       string[] input = {    
           "Given$a$text$file$of$many$lines,$where$fields$within$a$line$",
           "are$delineated$by$a$single$'dollar'$character,$write$a$program",
           "that$aligns$each$column$of$fields$by$ensuring$that$words$in$each$",
           "column$are$separated$by$at$least$one$space.",
           "Further,$allow$for$each$word$in$a$column$to$be$either$left$",
           "justified,$right$justified,$or$center$justified$within$its$column.",
       };
       foreach (string line in AlignColumns(input, JustifyCenter))
       {
           Console.WriteLine(line);
       }
   }

}</lang>

Output (centered):

  Given        a         text     file    of     many      lines,    where   fields  within    a    line
   are     delineated     by       a    single 'dollar'  character,  write      a    program            
   that      aligns      each    column   of    fields       by     ensuring  that    words    in   each
  column      are     separated    by     at     least      one      space.                             
 Further,    allow       for      each   word     in         a       column    to      be    either left
justified,   right    justified,   or   center justified   within     its    column.                    

Clojure

<lang Clojure> (ns rosettacode.align-columns

 (:require [clojure.contrib.string :as str]))

(def data "Given$a$text$file$of$many$lines,$where$fields$within$a$line$ are$delineated$by$a$single$'dollar'$character,$write$a$program that$aligns$each$column$of$fields$by$ensuring$that$words$in$each$ column$are$separated$by$at$least$one$space. Further,$allow$for$each$word$in$a$column$to$be$either$left$ justified,$right$justified,$or$center$justified$within$its$column.")

(def table (map #(str/split #"\$" %) (str/split-lines data)))

(defn col-width [n table] (reduce max (map #(try (count (nth % n))

                                              (catch Exception _  0))
                                          table)))

(defn spaces [n] (str/repeat n " ")) (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))]
       (case justification
             :right (str (spaces pad-len) string)
             :left  (str string (spaces pad-len))
             :center (str (spaces half-pad-len) string (spaces (- pad-len half-pad-len)))))))

(defn aligned-table

 "get the width of each column, then generate a new table with propper padding for eath item"
 ([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 print-table

 [table]
 (do (println)
     (print (str/join "" (flatten (interleave table (repeat "\n")))))))

(print-table (aligned-table table :center)) </lang>

Common Lisp

<lang lisp>(defun nonempty (seq)

 (position-if (lambda (x) (declare (ignore x)) t) seq))

(defun split (delim seq) "Splits seq on delim into a list of subsequences. Trailing empty subsequences are removed."

 (labels
     ((f (seq &aux (pos (position delim seq)))
         (if pos
           (cons
             (subseq seq 0 pos)
             (f (subseq seq (1+ pos))))
           (list seq))))
   (let*
       ((list (f seq))
        (end (position-if #'nonempty list :from-end t)))
     (subseq list 0 (1+ end)))))

(defun lengthen (list minlen filler-elem &aux (len (length list))) "Destructively pads list with filler-elem up to minlen."

 (if (< len minlen)
   (nconc list (make-list
     (- minlen len) :initial-element filler-elem))
   list))

(defun align-columns (text &key (align :left) &aux

   (fmtmod (case align
     (:left "@")
     (:right ":")
     (:center "@:")
     (t (error "Invalid alignment."))))
   (fields (mapcar
     (lambda (line) (split #\$ line))
     (split #\Newline text)))
   (mostcols (loop for l in fields maximize (length l)))
   widest)
 (setf fields (mapcar
   (lambda (l) (lengthen l mostcols ""))
   fields))
 (setf widest (loop
   for col below (length (first fields))
   collect (loop
     for row in fields maximize (length (elt row col)))))
 (format nil
   (with-output-to-string (s)
     (princ "~{~{" s)
     (dolist (w widest)
       (format s "~~~d~a<~~a~~>" (1+ w) fmtmod))
     (princ "~}~%~}" s))
   fields))</lang>

D

This example allows selection of right- and left-favoring center alignments, defaulting to left-favoring center alignment. <lang d>import std.stdio; import std.string; char[]text = "Given$a$text$file$of$many$lines,$where$fields$within$a$line$\n" "are$delineated$by$a$single$'dollar'$character,$write$a$program\n" "that$aligns$each$column$of$fields$by$ensuring$that$words$in$each$\n" "column$are$separated$by$at$least$one$space.\n" "Further,$allow$for$each$word$in$a$column$to$be$either$left$\n" "justified,$right$justified,$or$center$justified$within$its$column.";

enum PadType {

       LEFT,
       RIGHT,
       CENTER,
       LEFT_CENTER,
       RIGHT_CENTER

}

int main() {

       char[][]lines = text.split("\n");
       char[][][]words;
       int[]maxlens;
       foreach(line;lines) {
               words ~= line.split("$");
               // make sure we have enough slots in maxlens
               if (words[$-1].length > maxlens.length) {
                       maxlens.length = words[$-1].length;
               }
               foreach(i,word;words[$-1]) {
                       if (word.length > maxlens[i]) maxlens[i] = word.length;
               }
       }
       // output everything with all 3 padding types
       foreach(line;words) {
               foreach(i,ref word;line) {
                       writef("%s ",padData(word,maxlens[i],PadType.LEFT));
               }
               writefln("");
       }
       foreach(line;words) {
               foreach(i,ref word;line) {
                       writef("%s ",padData(word,maxlens[i],PadType.RIGHT));
               }
               writefln("");
       }
       foreach(line;words) {
               foreach(i,ref word;line) {
                       writef("%s ",padData(word,maxlens[i],PadType.CENTER));
               }
               writefln("");
       }
       return 0;

}

char[]padData(char[]data,int length,PadType type) {

       int diff = length - data.length;
       switch(type) {
       case PadType.CENTER:
       case PadType.LEFT_CENTER:
               // the +1 in the second part takes care of odd differences, since this is integer math
               // odd differences will result in a slight left-of-center alignment
               return repeat(" ",diff/2)~data~repeat(" ",(diff+1)/2);
       case PadType.RIGHT_CENTER:
               // the +1 in the second part takes care of odd differences, since this is integer math
               // odd differences will result in a slight right-of-center alignment
               return repeat(" ",(diff+1)/2)~data~repeat(" ",diff/2);
       case PadType.RIGHT:
               return repeat(" ",diff)~data;
       case PadType.LEFT:
               return data~repeat(" ",diff);
       }

}</lang>

Given      a          text       file   of     many      lines,     where    fields  within  a      line  
are        delineated by         a      single 'dollar'  character, write    a       program 
that       aligns     each       column of     fields    by         ensuring that    words   in     each  
column     are        separated  by     at     least     one        space.   
Further,   allow      for        each   word   in        a          column   to      be      either left  
justified, right      justified, or     center justified within     its      column. 
     Given          a       text   file     of      many     lines,    where  fields  within      a line  
       are delineated         by      a single  'dollar' character,    write       a program 
      that     aligns       each column     of    fields         by ensuring    that   words     in each  
    column        are  separated     by     at     least        one   space. 
  Further,      allow        for   each   word        in          a   column      to      be either left  
justified,      right justified,     or center justified     within      its column. 
  Given        a         text     file    of     many      lines,    where   fields  within    a    line  
   are     delineated     by       a    single 'dollar'  character,  write      a    program 
   that      aligns      each    column   of    fields       by     ensuring  that    words    in   each  
  column      are     separated    by     at     least      one      space.  
 Further,    allow       for      each   word     in         a       column    to      be    either left  
justified,   right    justified,   or   center justified   within     its    column.

Another version, using more the Phobos standard library.

Works with: D version 2.051

<lang d>import std.string, std.stdio, std.algorithm, std.typetuple ;

void alignText(string txt) {

   string[][] text ;
   uint maxCol = 0 ;
   foreach(l;txt.splitlines) {
       text ~= chomp(l.split("$"), [""]) ; // chomp work for string[] !!!
       maxCol = max(maxCol, text[$-1].length) ;
   }
   auto colMaxWidth = new uint[](maxCol) ;
   foreach(i, ref l;text)  {
       if(maxCol > l.length)
           l ~= repeat(" ", maxCol - l.length - 1).split(" ") ;
       foreach(idx,w;l)
           colMaxWidth[idx] = max(colMaxWidth[idx], w.length) ;
   }
   // display justified text
   foreach(justify;TypeTuple!(rjustify, center, ljustify)) {
       foreach(l;text) {
           foreach(idx,word;l)
               writef("%s|",justify(word,colMaxWidth[idx])) ;
           writeln() ;
       }
       writeln(" --- --- ") ;
   }

}</lang>



Delphi

<lang Delphi> USES

  StdCtrls, Classes, SysUtils, StrUtils, Contnrs;

procedure AlignByColumn(Output: TMemo; Align: TAlignment); const

  TextToAlign =
  'Given$a$text$file$of$many$lines,$where$fields$within$a$line$'#$D#$A +
  'are$delineated$by$a$single$dollar$character,$write$a$program'#$D#$A +
  'that$aligns$each$column$of$fields$by$ensuring$that$words$in$each$'#$D#$A +
  'column$are$separated$by$at$least$one$space.'#$D#$A +
  'Further,$allow$for$each$word$in$a$column$to$be$either$left$'#$D#$A +
  'justified,$right$justified,$or$center$justified$within$its$column.';

var

  TextLine, TempTString: TStringlist;
  TextLines: TObjectList;
  MaxLength, i, j: Byte;
  OutPutString, EmptyString, Item: String;

begin

  TRY
     MaxLength := 0;
     TextLines := TObjectList.Create(True);
     TextLine := TStringList.Create;
     TextLine.text := TextToAlign;
     for i:= 0 to TextLine.Count - 1 do
     begin
        TempTString := TStringlist.create;
        TempTString.text :=AnsiReplaceStr(TextLine[i], '$', #$D#$A);
        TextLines.Add(TempTString);
     end;
     for i := 0 to TextLines.Count - 1 do
        for j := 0 to TStringList(TextLines.Items[i]).Count - 1 do
           If Length(TStringList(TextLines.Items[i])[j]) > MaxLength then
              MaxLength := Length(TStringList(TextLines.Items[i])[j]);
     If MaxLength > 0 then
        MaxLength := MaxLength + 2; // Add to empty spaces to it
     for i := 0 to TextLines.Count - 1 do
     begin
        OutPutString := ;
        for j := 0 to TStringList(TextLines.Items[i]).Count - 1 do
        begin
           EmptyString := StringOfChar(' ', MaxLength);
           Item := TStringList(TextLines.Items[i])[j];
           case Align of
              taLeftJustify: Move(Item[1], EmptyString[2], Length(Item));
              taRightJustify: Move(Item[1], EmptyString[MaxLength - Length(Item) + 1], Length(Item));
              taCenter: Move(Item[1], EmptyString[(MaxLength - Length(Item) + 1) div 2 + 1], Length(Item));
           end;
           OutPutString := OutPutString + EmptyString;
        end;
        Output.Lines.Add(OutPutString);
     end;
  FINALLY
     FreeAndNil(TextLine);
     FreeAndNil(TextLines);
  END;

end; </lang>

E

<lang e>pragma.enable("accumulator")

def left(width, word) {

 return word + " " * (width - word.size())

}

def center(width, word) {

 def leftCount := (width - word.size()) // 2
 return " " * leftCount + word + " " * (width - word.size() - leftCount)

}

def right(width, word) {

 return " " * (width - word.size()) + word

}

def alignColumns(align, text) {

   def split := accum [] for line in text.split("\n") { _.with(line.split("$")) }
   var widths := []
   for line in split {
     for i => word in line {
       widths with= (i, widths.fetch(i, fn{0}).max(word.size()))
     }
   }
   return accum "" for line in split { 
     _ + accum "" for i => word in line {
       _ + align(widths[i] + 1, word)
     } + "\n"
   }

}</lang>

<lang e>? def text := "Given$a$text$file$of$many$lines,$where$fields$within$a$line$ are$delineated$by$a$single$'dollar'$character,$write$a$program that$aligns$each$column$of$fields$by$ensuring$that$words$in$each$ column$are$separated$by$at$least$one$space. Further,$allow$for$each$word$in$a$column$to$be$either$left$ justified,$right$justified,$or$center$justified$within$its$column."; null

? println(alignColumns(left, text)) Given a text file of many lines, where fields within a line are delineated by a single 'dollar' character, write a program that aligns each column of fields by ensuring that words in each column are separated by at least one space. Further, allow for each word in a column to be either left justified, right justified, or center justified within its column.

? println(alignColumns(center, text))

  Given        a        text     file    of      many     lines,     where   fields  within    a   line  
   are    delineated     by        a   single  'dollar' character,   write     a    program 
  that      aligns      each    column   of     fields      by     ensuring   that   words    in   each  
 column       are     separated   by     at     least       one     space.  
Further,     allow       for     each   word      in         a      column     to      be   either left  

justified, right justified, or center justified within its column.

? println(alignColumns(right, text))

     Given          a       text   file     of      many     lines,    where  fields  within      a line 
       are delineated         by      a single  'dollar' character,    write       a program
      that     aligns       each column     of    fields         by ensuring    that   words     in each 
    column        are  separated     by     at     least        one   space.
  Further,      allow        for   each   word        in          a   column      to      be either left 
justified,      right justified,     or center justified     within      its column.</lang>

Factor

<lang factor>USING: fry io kernel math math.functions math.order sequences splitting strings ; IN: rosetta.column-aligner

CONSTANT: example-text "Given$a$text$file$of$many$lines,$where$fields$within$a$line$ are$delineated$by$a$single$'dollar'$character,$write$a$program that$aligns$each$column$of$fields$by$ensuring$that$words$in$each$ column$are$separated$by$at$least$one$space. Further,$allow$for$each$word$in$a$column$to$be$either$left$ justified,$right$justified,$or$center$justified$within$its$column."

split-and-pad ( text -- lines )
   "\n" split [ "$" split harvest ] map
   dup [ length ] [ max ] map-reduce
   '[ _ "" pad-tail ] map ;
column-widths ( columns -- widths )
   [ [ length ] [ max ] map-reduce ] map ;

SINGLETONS: +left+ +middle+ +right+ ;

GENERIC: align-string ( str n alignment -- str' )

M: +left+ align-string drop CHAR: space pad-tail ; M: +right+ align-string drop CHAR: space pad-head ;

M: +middle+ align-string

   drop
   over length - 2 /
   [ floor CHAR: space <string> ]
   [ ceiling CHAR: space <string> ] bi surround ;
align-columns ( columns alignment -- columns' )
   [ dup column-widths ] dip '[
       [ _ align-string ] curry map
   ] 2map ;
print-aligned ( text alignment -- )
   [ split-and-pad flip ] dip align-columns flip
   [ [ write " " write ] each nl ] each ;</lang>
example-text { +left+ +middle+ +right+ } [ print-aligned ] with each

Forth

Works with: GNU Forth

<lang forth>\ align columns

split ( addr len char -- addr len1 addr len-len1 )
 >r 2dup r> scan 2swap 2 pick - ;

variable column

for-each-line ( file len xt -- )
 >r begin #lf split r@ execute 1 /string dup 0<= until 2drop rdrop ;
for-each-field ( line len xt -- )
 0 column !
 >r begin '$ split r@ execute 1 column +! 1 /string dup 0<= until 2drop rdrop ;

0 value num-columns

count-columns ( line len -- )
 ['] 2drop for-each-field
 num-columns column @ max to num-columns ;
find-num-columns ( file len -- )
 0 to num-columns
 ['] count-columns for-each-line ;

0 value column-widths

column-width ( field len -- )
 column-widths column @ + c@
 max
 column-widths column @ + c!
 drop ;
measure-widths ( line len -- )
 ['] column-width for-each-field ;
find-column-widths ( file len -- )
 num-columns allocate throw to column-widths
 column-widths num-columns erase
 ['] measure-widths for-each-line ;

\ type aligned, same naming convention as standard numeric U.R, .R

type.l ( addr len width -- )
 over -               >r type r>       spaces ;
type.c ( addr len width -- )
 over - dup 2/ spaces >r type r> 1+ 2/ spaces ;
type.r ( addr len width -- )
 over -        spaces    type ;

defer type.aligned

print-field ( field len -- )
 column-widths column @ + c@ type.aligned space ;
print-line ( line len -- ) cr ['] print-field for-each-field ;
print-fields ( file len -- ) ['] print-line for-each-line ;


\ read file s" columns.txt" slurp-file ( file len )

\ scan once to determine num-columns 2dup find-num-columns

\ scan again to determine column-widths 2dup find-column-widths

\ print columns, once for each alignment type ' type.l is type.aligned 2dup print-fields cr ' type.c is type.aligned 2dup print-fields cr ' type.r is type.aligned 2dup print-fields cr

\ cleanup nip free throw column-widths free throw</lang>

Go

<lang go>package main

import (

   "fmt"
   "strings"

)

const text = `Given$a$text$file$of$many$lines,$where$fields$within$a$line$ are$delineated$by$a$single$'dollar'$character,$write$a$program that$aligns$each$column$of$fields$by$ensuring$that$words$in$each$ column$are$separated$by$at$least$one$space. Further,$allow$for$each$word$in$a$column$to$be$either$left$ justified,$right$justified,$or$center$justified$within$its$column.`

type formatter struct {

   text  [][]string
   width []int

}

func newFormatter(text string) *formatter {

   var f formatter
   for _, line := range strings.Split(text, "\n", -1) {
       words := strings.Split(line, "$", -1)
       for words[len(words)-1] == "" {
           words = words[:len(words)-1]
       }
       f.text = append(f.text, words)
       for i, word := range words {
           if i == len(f.width) {
               f.width = append(f.width, len(word))
           } else if len(word) > f.width[i] {
               f.width[i] = len(word)
           }
       }
   }
   return &f

}

const (

   left = iota
   middle
   right

)

func (f *formatter) print(j int) {

   for _, line := range f.text {
       for i, word := range line {
           fmt.Printf("%-*s ", f.width[i], fmt.Sprintf("%*s",
               len(word)+(f.width[i]-len(word))*j/2, word))
       }
       fmt.Println("")
   }
   fmt.Println("")

}

func main() {

   f := newFormatter(text)
   f.print(left)
   f.print(middle)
   f.print(right)

}</lang>

Given      a          text       file   of     many      lines,     where    fields  within  a      line
are        delineated by         a      single 'dollar'  character, write    a       program
that       aligns     each       column of     fields    by         ensuring that    words   in     each
column     are        separated  by     at     least     one        space.
Further,   allow      for        each   word   in        a          column   to      be      either left
justified, right      justified, or     center justified within     its      column.

  Given        a         text     file    of     many      lines,    where   fields  within    a    line
   are     delineated     by       a    single 'dollar'  character,  write      a    program
   that      aligns      each    column   of    fields       by     ensuring  that    words    in   each
  column      are     separated    by     at     least      one      space.
 Further,    allow       for      each   word     in         a       column    to      be    either left
justified,   right    justified,   or   center justified   within     its    column.

     Given          a       text   file     of      many     lines,    where  fields  within      a line
       are delineated         by      a single  'dollar' character,    write       a program
      that     aligns       each column     of    fields         by ensuring    that   words     in each
    column        are  separated     by     at     least        one   space.
  Further,      allow        for   each   word        in          a   column      to      be either left
justified,      right justified,     or center justified     within      its column.

Groovy

Solution: <lang groovy>def alignColumns = { align, rawText ->

   def lines = rawText.tokenize('\n')
   def words = lines.collect { it.tokenize(/\$/) }
   def maxLineWords = words.collect {it.size()}.max()
   words = words.collect { line -> line + [] * (maxLineWords - line.size()) }
   def columnWidths = words.transpose().collect{ column -> column.collect { it.size() }.max() }
   def justify = [   Right  : { width, string -> string.padLeft(width) },
                           Left   : { width, string -> string.padRight(width) },
                           Center : { width, string -> string.center(width) }      ]
   def padAll = { pad, colWidths, lineWords -> [colWidths, lineWords].transpose().collect { pad(it) + ' ' } }
   words.each { padAll(justify[align], columnWidths, it).each { print it }; println() }

}</lang>

Test Program: <lang groovy>def rawTextInput = Given$a$text$file$of$many$lines,$where$fields$within$a$line$ are$delineated$by$a$single$'dollar'$character,$write$a$program that$aligns$each$column$of$fields$by$ensuring$that$words$in$each$ column$are$separated$by$at$least$one$space. Further,$allow$for$each$word$in$a$column$to$be$either$left$ justified,$right$justified,$or$center$justified$within$its$column.

['Left', 'Center', 'Right'].each { align ->

   println "${align} Justified:"
   alignColumns(align, rawTextInput)
   println()

}</lang>

Output:

Left Justified:
Given      a          text       file   of     many      lines,     where    fields  within  a      line 
are        delineated by         a      single 'dollar'  character, write    a       program             
that       aligns     each       column of     fields    by         ensuring that    words   in     each 
column     are        separated  by     at     least     one        space.                               
Further,   allow      for        each   word   in        a          column   to      be      either left 
justified, right      justified, or     center justified within     its      column.                     

Center Justified:
  Given        a         text     file    of     many      lines,    where   fields  within    a    line 
   are     delineated     by       a    single 'dollar'  character,  write      a    program             
   that      aligns      each    column   of    fields       by     ensuring  that    words    in   each 
  column      are     separated    by     at     least      one      space.                              
 Further,    allow       for      each   word     in         a       column    to      be    either left 
justified,   right    justified,   or   center justified   within     its    column.                     

Right Justified:
     Given          a       text   file     of      many     lines,    where  fields  within      a line 
       are delineated         by      a single  'dollar' character,    write       a program             
      that     aligns       each column     of    fields         by ensuring    that   words     in each 
    column        are  separated     by     at     least        one   space.                             
  Further,      allow        for   each   word        in          a   column      to      be either left 
justified,      right justified,     or center justified     within      its column.

Haskell

<lang haskell>import Data.List import Control.Monad import Control.Arrow

dat = "Given$a$text$file$of$many$lines,$where$fields$within$a$line$\n" ++

     "are$delineated$by$a$single$'dollar'$character,$write$a$program\n" ++
     "that$aligns$each$column$of$fields$by$ensuring$that$words$in$each$\n" ++
     "column$are$separated$by$at$least$one$space.\n" ++
     "Further,$allow$for$each$word$in$a$column$to$be$either$left$\n" ++
     "justified,$right$justified,$or$center$justified$within$its$column.\n"

brkdwn = takeWhile (not.null) . unfoldr (Just . second (drop 1) . span ('$'/=))

format j ls = map (unwords. zipWith align colw) rows

 where
   rows = map brkdwn $ lines ls
   colw = map (maximum. map length) . transpose $ rows
   align cw w =
     case j of
       'c' -> (replicate l ' ') ++ w ++ (replicate r ' ')
       'r' -> (replicate dl ' ') ++ w
       'l' -> w ++ (replicate dl ' ')
       where
          dl = cw-length w
          (l,r) = (dl `div` 2, dl-l)</lang>

output example:

*Main> mapM_ putStrLn $ format 'c' dat
  Given        a         text     file    of     many      lines,    where   fields  within    a    line
   are     delineated     by       a    single 'dollar'  character,  write      a    program
   that      aligns      each    column   of    fields       by     ensuring  that    words    in   each
  column      are     separated    by     at     least      one      space.
 Further,    allow       for      each   word     in         a       column    to      be    either left
justified,   right    justified,   or   center justified   within     its    column.

HicEst

A file opened with a Format option describing the column format(s) can be addressed like a standard in-memory array. In addition the DLG function (MatrixExplorer) allows this text/numeric file to be edited or visualized in many ways, but string columns are always left adjusted while numeric columns are right adjusted. Export is possible. <lang HicEst> CHARACTER Fnam = "\HicEst\Rosetta\Align columns.txt"

  OPEN(FIle=Fnam, Format="12$", LENgth=rows)

! call the DLG function in MatrixExplorer mode:

  DLG(Edit=Fnam, Format='12A10') ! left adjusted, 12 columns, 10 spaces each

! or the standard way:

  CALL Align( "LLLLLLLLLLL ", Fnam, rows)   ! left   align
  CALL Align( "CCCCCCCCCCC ", Fnam, rows)   ! center align
  CALL Align( "RRRRRRRRRRR ", Fnam, rows)   ! right  align

END

SUBROUTINE Align(picture, filename, rows)

  CHARACTER picture, filename
  CHARACTER out*400, txt*20
  W = LEN(picture)
  DO i = 1, rows
    out = " "
    DO j = 0, 100
      txt = filename(i, j+1, *9) ! on error branch to label 9
      WRITE(Text=out(j*W+1 : ), Format=picture) txt
    ENDDO
9 CONTINUE
  WRITE() out
  ENDDO

END</lang>

Given       a           text        file        of          many        lines,      where       fields      within      a           line
are         delineated  by          a           single      'dollar'    character,  write       a           program
that        aligns      each        column      of          fields      by          ensuring    that        words       in          each
column      are         separated   by          at          least       one         space.
Further,    allow       for         each        word        in          a           column      to          be          either      left
justified,  right       justified,  or          center      justified   within      its         column.
   Given         a         text        file         of         many       lines,       where      fields      within         a         line
    are     delineated      by           a        single     'dollar'   character,     write         a        program
   that       aligns       each       column        of        fields        by       ensuring      that        words        in         each
  column        are      separated      by          at         least        one       space.
 Further,      allow        for        each        word         in           a        column        to          be        either       left
justified,     right    justified,      or        center     justified    within        its       column.
      Given           a        text        file          of        many      lines,       where      fields      within           a        line
        are  delineated          by           a      single    'dollar'  character,       write           a     program
       that      aligns        each      column          of      fields          by    ensuring        that       words          in        each
     column         are   separated          by          at       least         one      space.
   Further,       allow         for        each        word          in           a      column          to          be      either        left
 justified,       right  justified,          or      center   justified      within         its     column.

Icon and Unicon

An argument of left, center, or right controls the column alignment. The default is left-alignment. <lang icon>global width

procedure main(args)

   lines := []
   width := 0
   format := left
   match("left"|"right"|"center", format <- !args)
   every put(lines,prepare(!&input))
   display(lines, proc(format,3))

end

procedure prepare(lines)

   line := []
   lines ? {
       while (not pos(0)) & (field := tab(upto('$')|0)) do {
           put(line, field)
           width <:= *field
           move(1)
           }
       }
   return line

end

procedure display(lines, format)

   width +:= 1
   every line := !lines do {
       every writes(format(!line, width))
       write()
       }

end</lang>

Sample run:

->align right <align.txt
      Given          a       text       file         of       many     lines,      where     fields     within          a       line
        are delineated         by          a     single   'dollar' character,      write          a    program
       that     aligns       each     column         of     fields         by   ensuring       that      words         in       each
     column        are  separated         by         at      least        one     space.
   Further,      allow        for       each       word         in          a     column         to         be     either       left
 justified,      right justified,         or     center  justified     within        its    column.
->

J

Solution <lang j>'LEFT CENTER RIGHT'=: i.3 NB. justification constants

NB.* alignCols v Format delimited text in justified columns NB. y: text to format NB. rows marked by last character in text NB. columns marked by $ NB. optional x: justification. Default is LEFT NB. result: text table alignCols=: verb define

 LEFT alignCols y                       NB. default
 global=. dyad def'9!:x y'each
 oldbox=. 6 16 global ;             NB. save settings
 7 17 global (11#' ');,~x               NB. apply new settings
 result=. _2{:\ ": <;._2 @:,&'$';._2 y  NB. parse & format text
 7 17 global oldbox                     NB. restore settings
 result

)</lang>

Example: <lang j> text=: noun define Given$a$text$file$of$many$lines,$where$fields$within$a$line$ are$delineated$by$a$single$'dollar'$character,$write$a$program that$aligns$each$column$of$fields$by$ensuring$that$words$in$each$ column$are$separated$by$at$least$one$space. Further,$allow$for$each$word$in$a$column$to$be$either$left$ justified,$right$justified,$or$center$justified$within$its$column. )

  alignCols text           NB. default justification
Given      a          text       file   of     many      lines,     where    fields  within  a      line  
are        delineated by         a      single 'dollar'  character, write    a       program              
that       aligns     each       column of     fields    by         ensuring that    words   in     each  
column     are        separated  by     at     least     one        space.                                
Further,   allow      for        each   word   in        a          column   to      be      either left  
justified, right      justified, or     center justified within     its      column.                      
  CENTER alignCols text    NB. specify desired justification as left argument
  Given        a         text     file    of     many      lines,    where   fields  within    a    line  
   are     delineated     by       a    single 'dollar'  character,  write      a    program              
   that      aligns      each    column   of    fields       by     ensuring  that    words    in   each  
  column      are     separated    by     at     least      one      space.                               
 Further,    allow       for      each   word     in         a       column    to      be    either left  
justified,   right    justified,   or   center justified   within     its    column.</lang>

JavaScript

<lang JavaScript> var justification="center", input=["Given$a$text$file$of$many$lines,$where$fields$within$a$line$", "are$delineated$by$a$single$'dollar'$character,$write$a$program", "that$aligns$each$column$of$fields$by$ensuring$that$words$in$each$", "column$are$separated$by$at$least$one$space.", "Further,$allow$for$each$word$in$a$column$to$be$either$left$", "justified,$right$justified,$or$center$justified$within$its$column."], x,y,cols,max,cols=0,diff,left,right

String.prototype.repeat=function(n){return new Array(1 + parseInt(n)).join(this);}

for(x=0;x<input.length;x++) {

input[x]=input[x].split("$");
if(input[x].length>cols) cols=input[x].length;

} for(x=0;x<cols;x++) {

max=0;
for(y=0;y<input.length;y++) if(input[y][x]&&max<input[y][x].length) max=input[y][x].length;
for(y=0;y<input.length;y++) 
 if(input[y][x]) {
  diff=(max-input[y][x].length)/2;
  left=" ".repeat(Math.floor(diff));
  right=" ".repeat(Math.ceil(diff));
  if(justification=="left") {right+=left;left=""}
  if(justification=="right") {left+=right;right=""}
  input[y][x]=left+input[y][x]+right;
 }

} for(x=0;x<input.length;x++) input[x]=input[x].join(" "); input=input.join("\n"); document.write(input);</lang>

Liberty BASIC

<lang lb>mainwin 140 32

   CRLF$  =chr$( 13)
   maxlen =0
   read y
   Dim txt$( y)
   For i =1 To y
       Read i$
       print i$
       if right$( i$, 1) <>"$" then i$ =i$ +"$"
       txt$( i) =i$
       x  =max( CountDollars( txt$( i)), x)
   Next i
   print x
   Dim matrix$( x, y)
   Print CRLF$; "  ---- Left ----"
   For yy =1 To y
       For xx =1 To x
           matrix$( xx, yy) =word$( txt$( yy), xx, "$")
           print matrix$( xx, yy), "|";
           maxlen           =max( maxlen, Len( matrix$( xx, yy)))
       Next xx
       print ""
   Next yy
   Print CRLF$; "  ---- Right ----"
   For yy =1 To y
       For xx =1 To x
           Print right$( "                    " +matrix$( xx, yy), maxlen +1); "|";
           '   will truncate column words longer than 20. Change to use maxlen....
       Next xx
       Print ""
   Next yy
   Print CRLF$ +"  ---- Center ----"
   For yy =1 to y
       For xx =1 to x
           wordLen     =Len( matrix$( xx, yy))
           padNeeded   =maxlen -wordLen +4
           LeftSpaces  =padNeeded /2
           if LeftSpaces =int( LeftSpaces) then
               RightSpaces =LeftSpaces
           else
               RightSpaces =LeftSpaces -1
           end if
           Print space$( LeftSpaces); matrix$( xx, yy); space$( RightSpaces); "|";
       Next xx
       Print ""
   Next yy
   wait
   Data  6
   Data "Given$a$text$file$of$many$lines,$where$fields$within$a$line$"
   Data "are$delineated$by$a$single$'dollar'$character,$write$a$program"
   Data "that$aligns$each$column$of$fields$by$ensuring$that$words$in$each$"
   Data "column$are$separated$by$at$least$one$space."
   Data "Further,$allow$for$each$word$in$a$column$to$be$either$left$"
   Data "justified,$right$justified,$or$center$justified$within$its$column."
   function CountDollars( src$)
       c =0
       for j =1 to len( src$)
           if mid$( src$, j, 1) ="$" then c =c +1
       next j
       CountDollars =c
   end function
   end</lang>

Lua

Works with: Lua version 5.1

<lang lua> local tWord = {} -- word table local tColLen = {} -- maximum word length in a column local rowCount = 0 -- row counter --store maximum column lengths at 'tColLen'; save words into 'tWord' table local function readInput(pStr)

   for line in pStr:gmatch("([^\n]+)[\n]-") do  -- read until '\n' character
       rowCount = rowCount + 1
       tWord[rowCount] = {}                     -- create new row
       local colCount = 0
       for word in line:gmatch("[^$]+") do      -- read non '$' character
           colCount = colCount + 1
           tColLen[colCount] = math.max((tColLen[colCount] or 0), #word)   -- store column length
           tWord[rowCount][colCount] = word                                -- store words
       end--for word
   end--for line

end--readInput --repeat space to align the words in the same column local align = {

   ["left"] = function (pWord, pColLen)
       local n = (pColLen or 0) - #pWord + 1
       return pWord .. (" "):rep(n)
   end;--["left"]
   ["right"] = function (pWord, pColLen)
       local n = (pColLen or 0) - #pWord + 1
       return (" "):rep(n) .. pWord
   end;--["right"]
   ["center"] = function (pWord, pColLen)
       local n = (pColLen or 0) - #pWord + 1
       local n1 = math.floor(n/2)
       return (" "):rep(n1) .. pWord .. (" "):rep(n-n1)
   end;--["center"]

} --word table padder local function padWordTable(pAlignment)

   local alignFunc = align[pAlignment]                         -- selecting the spacer function
   for rowCount, tRow in ipairs(tWord) do
       for colCount, word in ipairs(tRow) do
           tRow[colCount] = alignFunc(word, tColLen[colCount]) -- save the padded words into the word table
       end--for colCount, word
   end--for rowCount, tRow

end--padWordTable --main interface


[]

function alignColumn(pStr, pAlignment, pFileName)


[]

   readInput(pStr)                           -- store column lengths and words
   padWordTable(pAlignment or "left")        -- pad the stored words
   local output = ""
   for rowCount, tRow in ipairs(tWord) do
       local line = table.concat(tRow)       -- concatenate words in one row
       print(line)                           -- print the line
       output = output .. line .. "\n"       -- concatenate the line for output, add line break
   end--for rowCount, tRow
   if (type(pFileName) == "string") then
       local file = io.open(pFileName, "w+")
       file:write(output)                    -- write output to file
       file:close()
   end--if type(pFileName)
   return output

end--alignColumn </lang>

Usage Example:

<lang lua> input = [[Given$a$text$file$of$many$lines,$where$fields$within$a$line$ are$delineated$by$a$single$'dollar'$character,$write$a$program that$aligns$each$column$of$fields$by$ensuring$that$words$in$each$ column$are$separated$by$at$least$one$space. Further,$allow$for$each$word$in$a$column$to$be$either$left$ justified,$right$justified,$or$center$justified$within$its$column.]]


outputLeft = alignColumn(input) outputRight = alignColumn(input, "right") alignColumn(input, "center", "output.txt") </lang>

MUMPS

<lang MUMPS>columns(how) ; how = "Left", "Center" or "Right" New col,half,ii,max,spaces,word Set ii=0 Set ii=ii+1,line(ii)="Given$a$text$file$of$many$lines,$where$fields$within$a$line$" Set ii=ii+1,line(ii)="are$delineated$by$a$single$'dollar'$character,$write$a$program" Set ii=ii+1,line(ii)="that$aligns$each$column$of$fields$by$ensuring$that$words$in$each$" Set ii=ii+1,line(ii)="column$are$separated$by$at$least$one$space." Set ii=ii+1,line(ii)="Further,$allow$for$each$word$in$a$column$to$be$either$left$" Set ii=ii+1,line(ii)="justified,$right$justified,$or$center$justified$within$its$column." Set ii="" For Set ii=$Order(line(ii)) Quit:ii="" Do . For col=1:1:$Length(line(ii),"$") Do . . Set max=$Length($Piece(line(ii),"$",col)) . . Set:max>$Get(max(col)) max(col)=max . . Quit . Quit Set ii="" For Set ii=$Order(line(ii)) Quit:ii="" Do . Write ! For col=1:1:$Length(line(ii),"$") Do:$Get(max(col)) . . Set word=$Piece(line(ii),"$",col) . . Set spaces=$Justify("",max(col)-$Length(word)) . . If how="Left" Write word,spaces," " Quit . . If how="Right" Write spaces,word," " Quit . . Set half=$Length(spaces)\2 . . Write $Extract(spaces,1,half),word,$Extract(spaces,half+1,$Length(spaces))," " . . Quit . Quit Write ! Quit Do columns("Left")

Given a text file of many lines, where fields within a line are delineated by a single 'dollar' character, write a program that aligns each column of fields by ensuring that words in each column are separated by at least one space. Further, allow for each word in a column to be either left justified, right justified, or center justified within its column.

Do columns("Center")

 Given        a         text     file    of     many      lines,    where   fields  within    a    line
  are     delineated     by       a    single 'dollar'  character,  write      a    program
  that      aligns      each    column   of    fields       by     ensuring  that    words    in   each
 column      are     separated    by     at     least      one      space.
Further,    allow       for      each   word     in         a       column    to      be    either left

justified, right justified, or center justified within its column.

Do columns("Right")

    Given          a       text   file     of      many     lines,    where  fields  within      a line
      are delineated         by      a single  'dollar' character,    write       a program
     that     aligns       each column     of    fields         by ensuring    that   words     in each
   column        are  separated     by     at     least        one   space.
 Further,      allow        for   each   word        in          a   column      to      be either left

justified, right justified, or center justified within its column.</lang>


OCaml

<lang ocaml>#load "str.cma" open Str

let input = "\ Given$a$text$file$of$many$lines,$where$fields$within$a$line$ are$delineated$by$a$single$'dollar'$character,$write$a$program that$aligns$each$column$of$fields$by$ensuring$that$words$in$each$ column$are$separated$by$at$least$one$space. Further,$allow$for$each$word$in$a$column$to$be$either$left$ justified,$right$justified,$or$center$justified$within$its$column."

let () =

 let lines = split (regexp_string "\n") input in
 let fields_l = List.map (split (regexp_string "$")) lines in
 let fields_l = List.map Array.of_list fields_l in
 let n = (* number of columns *)
   List.fold_left
     (fun n fields -> max n (Array.length fields))
     0 fields_l
 in
 let pads = Array.make n 0 in
 List.iter (
   (* calculate the max padding for each column *)
   Array.iteri
     (fun i word -> pads.(i) <- max pads.(i) (String.length word))
 ) fields_l;
 let print f =
   List.iter (fun fields ->
     Array.iteri (fun i word ->
       f word (pads.(i) - (String.length word))
     ) fields;
     print_newline()
   ) fields_l;
 in
 (* left column-aligned output *)
 print (fun word pad ->
   let spaces = String.make pad ' ' in
   Printf.printf "%s%s " word spaces);
 (* right column-aligned output *)
 print (fun word pad ->
   let spaces = String.make pad ' ' in
   Printf.printf "%s%s " spaces word);
 (* center column-aligned output *)
 print (fun word pad ->
   let pad1 = pad / 2 in
   let pad2 = pad - pad1 in
   let sp1 = String.make pad1 ' ' in
   let sp2 = String.make pad2 ' ' in
   Printf.printf "%s%s%s " sp1 word sp2);
</lang>

Oz

<lang oz>declare

 %% Lines: list of strings
 %% Alignment: function like fun {Left Txt ExtraSpace} ... end
 %% Returns: list of aligned (virtual) strings
 fun {Align Lines Alignment}
    ParsedLines = {Map Lines ParseLine}
    NumColumns = {Maximum {Map ParsedLines Record.width}}
    %% maps column index to column width:
    WidthOfColumn = {Record.map {TupleRange NumColumns}
                     fun {$ ColumnIndex}
                        fun {LengthOfThisColumn ParsedLine}
                           {Length {CondSelect ParsedLine ColumnIndex nil}}
                        end
                     in
                        {Maximum {Map ParsedLines LengthOfThisColumn}}
                     end}
 in
    {Map ParsedLines
     fun {$ Columns}
        {Record.mapInd Columns
         fun {$ ColumnIndex ColumnText}
            Extra = WidthOfColumn.ColumnIndex - {Length ColumnText}
         in
            {Alignment ColumnText Extra}#" "
         end}
     end}
 end
 %% A parsed line is a tuple of columns.
 %% "a$b$c" -> '#'(1:"a" 2:"b" 3:"c")
 fun {ParseLine Line}
    {List.toTuple '#' {String.tokens Line &$}}
 end
 %% possible alignments:
 
 fun {Left Txt Extra}
    Txt#{Spaces Extra}
 end
 fun {Right Txt Extra}
    {Spaces Extra}#Txt
 end
 fun {Center Txt Extra}
    Half = Extra div 2
 in
    {Spaces Half}#Txt#{Spaces Half + Extra mod 2}
 end
 %% helpers:
 
 %% 3 -> unit(1 2 3)
 fun {TupleRange Max}
    {List.toTuple unit {List.number 1 Max 1}}
 end
 fun {Maximum X|Xr}
    {FoldL Xr Value.max X}
 end
 fun {Spaces N}
    case N of 0 then nil
    else & |{Spaces N-1}
    end   
 end
 Lines = ["Given$a$text$file$of$many$lines,$where$fields$within$a$line$"
          "are$delineated$by$a$single$'dollar'$character,$write$a$program"
          "that$aligns$each$column$of$fields$by$ensuring$that$words$in$each$"
          "column$are$separated$by$at$least$one$space."
          "Further,$allow$for$each$word$in$a$column$to$be$either$left$"
          "justified,$right$justified,$or$center$justified$within$its$column."]

in

 {ForAll {Align Lines Left} System.showInfo}</lang>

Perl

<lang Perl>#/usr/bin/perl -w use strict ;

die "Call : perl columnaligner.pl <inputfile> <printorientation>!\n" unless

  @ARGV == 2 ; #$ARGV[ 0 ] contains example file , $ARGV[1] any of 'left' , 'right' or 'center'

die "last argument must be one of center, left or right!\n" unless

  $ARGV[ 1 ] =~ /center|left|right/ ;

sub printLines( $$$ ) ; open INFILE , "<" , "$ARGV[ 0 ]" or die "Can't open $ARGV[ 0 ]!\n" ; my @lines = <INFILE> ; close INFILE ; chomp @lines ; my @fieldwidths = map length, split /\$/ , $lines[ 0 ] ; foreach my $i ( 1..$#lines ) {

  my @words = split /\$/ , $lines[ $i ] ;
  foreach my $j ( 0..$#words ) {
     if ( $j <= $#fieldwidths ) {
        if ( length $words[ $j ] > $fieldwidths[ $j ] ) {
              $fieldwidths[ $j ] = length $words[ $j ] ;
        }
     }
     else {
        push @fieldwidths, length $words[ $j ] ;
     }
  }

} printLine( $_ , $ARGV[ 1 ] , \@fieldwidths ) foreach @lines ;

                                                                                                                                    1. ####

sub printLine {

  my $line = shift ;
  my $orientation = shift ;
  my $widthref = shift ;
  my @words = split /\$/, $line ;
  foreach my $k ( 0..$#words ) {
     my $printwidth = $widthref->[ $k ] + 1 ;
     if ( $orientation eq 'center' ) {
        $printwidth++ ;
     }
     if ( $orientation eq 'left' ) {
        print $words[ $k ] ;
        print " " x ( $printwidth - length $words[ $k ] ) ;
     }
     elsif ( $orientation eq 'right' ) {
        print " " x ( $printwidth - length $words[ $k ] ) ;
        print $words[ $k ] ;
     }
     elsif ( $orientation eq 'center' ) {
        my $left = int( ( $printwidth - length $words[ $k ] )     / 2 ) ;
        my $right = $printwidth - length( $words[ $k ] ) - $left      ;
        print " " x $left ;
        print $words[ $k ] ;
        print " " x $right ;
     }
  }
  print "\n" ;

}</lang> a shorter solution <lang perl>use List::Util qw(max);

sub columns {

   my @lines = map [split /\$/] => split /\n/ => shift;
   my $pos = {qw/left 0 center 1 right 2/}->{+shift};
   for my $col (0 .. max map {$#$_} @lines) {
       my $max = max my @widths = map {length $_->[$col]} @lines;
       for my $row (0 .. $#lines) {
           my @pad = map {' ' x $_, ' ' x ($_ + 0.5)} ($max - $widths[$row]) / 2;
           for ($lines[$row][$col])
               {$_ = join  => @pad[0 .. $pos-1], $_, @pad[$pos .. $#pad]}
       }
   }
   join  => map {"@$_\n"} @lines

}

print columns <<'END', $_ for qw(left right center); Given$a$text$file$of$many$lines,$where$fields$within$a$line$ are$delineated$by$a$single$'dollar'$character,$write$a$program that$aligns$each$column$of$fields$by$ensuring$that$words$in$each$ column$are$separated$by$at$least$one$space. Further,$allow$for$each$word$in$a$column$to$be$either$left$ justified,$right$justified,$or$center$justified$within$its$column. END</lang>

Perl 6

<lang Perl 6>###to be called with perl6 columnaligner.pl <orientation>(left, center , right )

      1. with left as default

my $fh = open "example.txt" , :r or die "Can't read text file!\n" ; my @filelines = $fh.lines ; close $fh ; my @maxcolwidths ; #array of the longest words per column

                  1. fill the array with values#####################

for @filelines -> $line {

  my @words = $line.split( "\$" ) ;
  for 0..@words.elems - 1 -> $i {
     if @maxcolwidths[ $i ] {

if @words[ $i ].chars > @maxcolwidths[$i] { @maxcolwidths[ $i ] = @words[ $i ].chars ; }

     }
     else {

@maxcolwidths.push( @words[ $i ].chars ) ;

     }
  }

} my $justification = @*ARGS[ 0 ] || "left" ;

    1. print lines , $gap holds the number of spaces, 1 to be added
    2. to allow for space preceding or following longest word

for @filelines -> $line {

  my @words = $line.split( "\$" ) ;
  for 0..@words.elems - 1 -> $i {
     my $gap =  @maxcolwidths[$i] - @words[$i].chars + 1 ;
     if $justification eq "left" {

print @words[ $i ] ~ " " x $gap ;

     } elsif $justification eq "right" {

print " " x $gap ~ @words[$i] ;

     } elsif $justification eq "center" {

$gap = ( @maxcolwidths[ $i ] + 2 - @words[$i].chars ) div 2 ; print " " x $gap ~ @words[$i] ~ " " x $gap ;

     }
  }
  say ; #for the newline

}</lang>

Or another way. To be called exactly as the first script. <lang Perl 6>my @lines = slurp("example.txt").lines; my @widths;

for @lines { for .split('$').kv { @widths[$^key] max= $^word.chars; } } for @lines { say .split('$').kv.map: { (align @widths[$^key], $^word) ~ " "; } }

sub align($column_width, $word, $aligment = @*ARGS[0]) {

       my $lr = $column_width - $word.chars;
       my $c  = $lr/2;
       return do given ($aligment) {
               when ("center") { " " x $c.ceiling ~ $word ~ " " x $c.floor }
               when ("right" ) { " " x $lr        ~ $word                  }
               default         {                    $word ~ " " x $lr      }
       }

}</lang>

PHP

<lang php><?php $j2justtype = array('L' => STR_PAD_RIGHT,

                   'R' => STR_PAD_LEFT,
                   'C' => STR_PAD_BOTH);

/**

Justify columns of textual tabular input where the record separator is the newline
and the field separator is a 'dollar' character.
justification can be L, R, or C; (Left, Right, or Centered).

Return the justified output as a string
  • /

function aligner($str, $justification = 'L') {

 global $j2justtype;
 assert(array_key_exists($justification, $j2justtype));
 $justtype = $j2justtype[$justification];
 $fieldsbyrow = array();
 foreach (explode("\n", $str) as $line)
   $fieldsbyrow[] = explode('$', $line);
 $maxfields = max(array_map('count', $fieldsbyrow));
 foreach (range(0, $maxfields-1) as $col) {
   $maxwidth = 0;
   foreach ($fieldsbyrow as $fields)
     $maxwidth = max($maxwidth, strlen($fields[$col]));
   foreach ($fieldsbyrow as &$fields)
     $fields[$col] = str_pad($fields[$col], $maxwidth, ' ', $justtype);
   unset($fields); // see http://bugs.php.net/29992
 }
 $result = ;
 foreach ($fieldsbyrow as $fields)
   $result .= implode(' ', $fields) . "\n";
 return $result;

}

$textinfile = 'Given$a$text$file$of$many$lines,$where$fields$within$a$line$ are$delineated$by$a$single$\'dollar\'$character,$write$a$program that$aligns$each$column$of$fields$by$ensuring$that$words$in$each$ column$are$separated$by$at$least$one$space. Further,$allow$for$each$word$in$a$column$to$be$either$left$ justified,$right$justified,$or$center$justified$within$its$column.';

foreach (array('L', 'R', 'C') as $j)

 echo aligner($textinfile, $j);

?></lang>

PicoLisp

<lang PicoLisp>(let Sizes NIL # Build a list of sizes

  (let Lines                          # and of lines
     (make
        (in "input.txt"                     # Reading input file
           (while (split (line) "$")        # delimited by '$'
              (let (L (link (mapcar pack @))  S Sizes)
                 (setq Sizes                   # Maintain sizes
                    (make
                       (while (or L S)
                          (link
                             (max
                                (inc (length (pop 'L)))
                                (pop 'S) ) ) ) ) ) ) ) ) )
     (for L Lines                                 # Print lines
        (prinl (apply align L (mapcar - Sizes))) )   # left aligned
     (prinl)
     (for L Lines
        (prinl (apply align L Sizes)) )              # right aligned
     (prinl)
     (for L Lines
        (prinl (apply center L Sizes)) ) ) )         # and centered</lang>

Output:

Given      a          text       file   of     many      lines,     where    fields  within  a      line  
are        delineated by         a      single 'dollar'  character, write    a       program              
that       aligns     each       column of     fields    by         ensuring that    words   in     each  
column     are        separated  by     at     least     one        space.                                
Further,   allow      for        each   word   in        a          column   to      be      either left  
justified, right      justified, or     center justified within     its      column.                      

      Given          a       text   file     of      many     lines,    where  fields  within      a line 
        are delineated         by      a single  'dollar' character,    write       a program             
       that     aligns       each column     of    fields         by ensuring    that   words     in each 
     column        are  separated     by     at     least        one   space.                             
   Further,      allow        for   each   word        in          a   column      to      be either left 
 justified,      right justified,     or center justified     within      its column.                     

   Given        a        text     file    of      many     lines,     where   fields  within    a   line 
    are    delineated     by        a   single  'dollar' character,   write     a    program             
   that      aligns      each    column   of     fields      by     ensuring   that   words    in   each 
  column       are     separated   by     at     least       one     space.                              
 Further,     allow       for     each   word      in         a      column     to      be   either left 
justified,    right   justified,   or   center justified   within      its   column.                     

PL/I

<lang PL/I> declare text character (300) varying; declare word character (20) varying; declare justification character (1); declare k fixed binary; declare input file, output file output;

open file (input) title ( '/CENTER.DAT,type(text),recsize(1000)' ); open file (output) title ( '/OUT.TXT,type(text),recsize(1000)' ); on endfile (input) stop;

display ('Specify whether justification is left, centered, or right'); display ('Reply with a single letter: L, C, or R'); get edit (justification) (A(1));

do forever;

  get file (input) edit (text) (L);
  put skip list (text);
  text = trim(text, '$', '$');
  do until (k = 0);
     k = index(text, '$');
     if k = 0 then /* last word in line */
        word = text;
     else
        do;
           word = substr(text, 1, k-1);
           text = substr(text, k);
           text = trim(text, '$');
        end;
     select (justification);
        when ('C', 'c') word = center(word, maxlength(word));
        when ('R', 'r') word = right (word, maxlength(word));
        otherwise ; /* The default is left adjusted. */
     end;
     put file (output) edit (word) (a(maxlength(word)));
  end;
  put file (output) skip;

end; </lang>


Prolog

Works with SWI-Prolog. <lang Prolog>aligner :- L ="Given$a$text$file$of$many$lines,$where$fields$within$a$line$ are$delineated$by$a$single$'dollar'$character,$write$a$program that$aligns$each$column$of$fields$by$ensuring$that$words$in$each$ column$are$separated$by$at$least$one$space. Further,$allow$for$each$word$in$a$column$to$be$either$left$ justified,$right$justified,$or$center$justified$within$its$column.",

% read the lines and the words % compute the length of the longuest word. % LP is the list of lines, % each line is a list of words parse(L, 0, N, LP, []),

% we need to add 1 to aligned N1 is N+1, % words will be left aligned sformat(AL, '~~w~~t~~~w|', [N1]), % words will be centered sformat(AC, '~~t~~w~~t~~~w|', [N1]), % words will be right aligned sformat(AR, '~~t~~w~~~w|', [N1]),

write('Left justified :'), nl, maplist(affiche(AL), LP), nl, write('Centered justified :'), nl, maplist(affiche(AC), LP), nl, write('Right justified :'), nl, maplist(affiche(AR), LP), nl.

affiche(F, L) :- maplist(my_format(F), L), nl.

my_format(_F, [13]) :- nl.

my_format(F, W) :- string_to_atom(W,AW), sformat(AF, F, [AW]), write(AF).


parse([], Max, Max) --> [].

parse(T, N, Max) --> { parse_line(T, 0, N1, T1, L, []), ( N1 > N -> N2 = N1; N2 = N)}, [L], parse(T1, N2, Max).

parse_line([], NF, NF, []) --> [].

parse_line([H|TF], NF, NF, TF) --> {code_type(H, end_of_line), !}, [].


parse_line(T, N, NF, TF) --> { parse_word(T, 0, N1, T1, W, []), ( N1 > N -> N2 = N1; N2 = N)}, [W], parse_line(T1, N2, NF, TF).

% 36 is the code of '$' parse_word([36|T], N, N, T) --> {!}, [].

parse_word([H|T], N, N, [H|T]) --> {code_type(H, end_of_line), !}, [].

parse_word([], N, N, []) --> [].

parse_word([H|T], N1, NF, TF) --> [H], {N2 is N1 + 1}, parse_word(T, N2, NF, TF). </lang>

Output :

 ?- aligner.
Left justified :
Given      a          text       file       of         many       lines,     where      fields     within     a          line       
are        delineated by         a          single     'dollar'   character, write      a          program    
that       aligns     each       column     of         fields     by         ensuring   that       words      in         each       
column     are        separated  by         at         least      one        space.     
Further,   allow      for        each       word       in         a          column     to         be         either     left       
justified, right      justified, or         center     justified  within     its        column.    

Centered justified :
   Given        a        text       file        of        many      lines,      where     fields     within        a        line    
    are    delineated     by          a       single    'dollar'  character,    write        a       program  
   that      aligns      each      column       of       fields       by      ensuring     that       words       in        each    
  column       are     separated     by         at        least       one      space.   
 Further,     allow       for       each       word        in          a       column       to         be       either      left    
justified,    right   justified,     or       center    justified   within       its      column.  

Right justified :
      Given          a       text       file         of       many     lines,      where     fields     within          a       line
        are delineated         by          a     single   'dollar' character,      write          a    program
       that     aligns       each     column         of     fields         by   ensuring       that      words         in       each
     column        are  separated         by         at      least        one     space.
   Further,      allow        for       each       word         in          a     column         to         be     either       left
 justified,      right justified,         or     center  justified     within        its    column.

true .

PureBasic

Works with: PureBasic version 4.41

<lang PureBasic>Declare max(a,b)

If OpenConsole()

 Define a, i, x, y, maxlen
 Dim txt.s(0)
 Restore lines             ; Get address of the first data block 
 Read.i  a
 ReDim txt(a)
 For i=0 To a              ; Read the raw data lines
   Read.s txt(i)
   txt(i)=Trim(txt(i),"$") ; Remove any bad '$' that may be useless in the end...
   x=max(CountString(txt(i),"$"),x)
 Next
 y=a
 Dim matrix.s(x,y)         ; Set up a nice matrix to work with, each word cleanly separated
 For x=0 To ArraySize(matrix(),1)
   For y=0 To ArraySize(matrix(),2)
     matrix(x,y)=StringField(txt(y),x+1,"$")
     maxlen=max(maxlen,Len(matrix(x,y)))
   Next
 Next
 If maxlen%2
   maxlen+1                ; Just to make sure that 'centered' output looks nice....
 EndIf
 
 PrintN(#CRLF$+"---- Right ----")
 For y=0 To ArraySize(matrix(),2)
   For x=0 To ArraySize(matrix(),1)
     Print(RSet(matrix(x,y),maxlen+1))
   Next
   PrintN("")
 Next
 
 PrintN(#CRLF$+"---- Left ----")
 For y=0 To ArraySize(matrix(),2)
   For x=0 To ArraySize(matrix(),1)
     Print(LSet(matrix(x,y),maxlen+1))
   Next
   PrintN("")
 Next
 
 PrintN(#CRLF$+"---- Center ----")
 For y=0 To ArraySize(matrix(),2)
   For x=0 To ArraySize(matrix(),1)
     a=maxlen-Len(matrix(x,y))
     Print(LSet(RSet(matrix(x,y),maxlen-a/2),maxlen))
   Next
   PrintN("")
 Next
 
 PrintN(#CRLF$+#CRLF$+"Press ENTER to quit."): Input()
 CloseConsole()

EndIf


Procedure max(x,y)

 If x>=y
   ProcedureReturn x
 Else
   ProcedureReturn y
 EndIf

EndProcedure


DataSection lines:

 Data.i  5 ; e.g. 6-1 since first line is equal to 'zero'.

text:

 Data.s "Given$a$text$file$of$many$lines,$where$fields$within$a$line$"
 Data.s "are$delineated$by$a$single$'dollar'$character,$write$a$program"
 Data.s "that$aligns$each$column$of$fields$by$ensuring$that$words$in$each$"
 Data.s "column$are$separated$by$at$least$one$space."
 Data.s "Further,$allow$for$each$word$in$a$column$oo$be$either$left$"
 Data.s "justified,$right$justified,$or$center$justified$within$its$column."

EndDataSection</lang>

Python

<lang python>from StringIO import StringIO

textinfile = Given$a$text$file$of$many$lines,$where$fields$within$a$line$ are$delineated$by$a$single$'dollar'$character,$write$a$program that$aligns$each$column$of$fields$by$ensuring$that$words$in$each$ column$are$separated$by$at$least$one$space. Further,$allow$for$each$word$in$a$column$to$be$either$left$ justified,$right$justified,$or$center$justified$within$its$column.

j2justifier = dict(L=str.ljust, R=str.rjust, C=str.center)

def aligner(infile, justification = 'L'):

  \
 Justify columns of textual tabular input where the row separator is the newline
 and the field separator is a 'dollar' character.
 justification can be L, R, or C; (Left, Right, or Centered).

 Return the justified output as a string
 
 assert justification in j2justifier, "justification can be L, R, or C; (Left, Right, or Centered)."
 justifier = j2justifier[justification]

 fieldsbyrow= [line.strip().split('$') for line in infile]
 # pad to same number of fields per row
 maxfields = max(len(row) for row in fieldsbyrow)
 fieldsbyrow = [fields + []*(maxfields - len(fields))
                   for fields in fieldsbyrow]
 # rotate
 fieldsbycolumn = zip(*fieldsbyrow)
 # calculate max fieldwidth per column
 colwidths = [max(len(field) for field in column)
              for column in fieldsbycolumn]
 # pad fields in columns to colwidth with spaces
 fieldsbycolumn = [ [justifier(field, width) for field in column]
                    for width, column in zip(colwidths, fieldsbycolumn) ]
 # rotate again
 fieldsbyrow = zip(*fieldsbycolumn)

 return "\n".join( " ".join(row) for row in fieldsbyrow)


for align in 'Left Right Center'.split():

 infile = StringIO(textinfile)
 print "\n# %s Column-aligned output:" % align
 print aligner(infile, align[0])</lang>

Example output:

# Left Column-aligned output:
Given      a          text       file   of     many      lines,     where    fields  within  a      line 
are        delineated by         a      single 'dollar'  character, write    a       program             
that       aligns     each       column of     fields    by         ensuring that    words   in     each 
column     are        separated  by     at     least     one        space.                               
Further,   allow      for        each   word   in        a          column   to      be      either left 
justified, right      justified, or     center justified within     its      column.                     

# Right Column-aligned output:
     Given          a       text   file     of      many     lines,    where  fields  within      a line 
       are delineated         by      a single  'dollar' character,    write       a program             
      that     aligns       each column     of    fields         by ensuring    that   words     in each 
    column        are  separated     by     at     least        one   space.                             
  Further,      allow        for   each   word        in          a   column      to      be either left 
justified,      right justified,     or center justified     within      its column.                     

# Center Column-aligned output:
  Given        a         text     file    of      many     lines,    where    fields  within   a    line 
   are     delineated     by       a    single  'dollar' character,  write      a    program             
   that      aligns      each    column   of     fields      by     ensuring   that   words    in   each 
  column      are     separated    by     at     least      one      space.                              
 Further,    allow       for      each   word      in        a       column     to      be   either left 
justified,   right    justified,   or   center justified   within     its    column.                     

R

<lang R># Read in text lines <- readLines(tc <- textConnection("Given$a$text$file$of$many$lines,$where$fields$within$a$line$ are$delineated$by$a$single$'dollar'$character,$write$a$program that$aligns$each$column$of$fields$by$ensuring$that$words$in$each$ column$are$separated$by$at$least$one$space. Further,$allow$for$each$word$in$a$column$to$be$either$left$ justified,$right$justified,$or$center$justified$within$its$column.")); close(tc)

  1. Split words by the dollar

words <- strsplit(lines, "\\$")

  1. Reformat

maxlen <- max(sapply(words, length)) words <- lapply(words, function(x) {length(x) <- maxlen; x}) block <- matrix(unlist(words), byrow=TRUE, ncol=maxlen) block[is.na(block)] <- "" leftjust <- format(block) rightjust <- format(block, justify="right") centrejust <- format(block, justify="centre")

  1. Print

print0 <- function(x) invisible(apply(x, 1, function(x) cat(x, "\n"))) print0(leftjust) print0(rightjust) print0(centrejust)</lang> Right justified output shown.

     Given          a       text       file         of       many     lines,      where     fields     within          a       line 
       are delineated         by          a     single   'dollar' character,      write          a    program                       
      that     aligns       each     column         of     fields         by   ensuring       that      words         in       each 
    column        are  separated         by         at      least        one     space.                                             
  Further,      allow        for       each       word         in          a     column         to         be     either       left 
justified,      right justified,         or     center  justified     within        its    column.                                  

REBOL

<lang rebol>REBOL [ Title: "Align Columns" Author: oofoe Date: 2010-09-29 URL: http://rosettacode.org/wiki/Align_columns ]

specimen: {Given$a$text$file$of$many$lines,$where$fields$within$a$line$ are$delineated$by$a$single$'dollar'$character,$write$a$program that$aligns$each$column$of$fields$by$ensuring$that$words$in$each$ column$are$separated$by$at$least$one$space. Further,$allow$for$each$word$in$a$column$to$be$either$left$ justified,$right$justified,$or$center$justified$within$its$column.}

Parse specimen into data grid.

data: copy [] foreach line parse specimen to-string lf [ ; Break into lines. append/only data parse line "$"  ; Break into columns. ]

Compute independent widths for each column.

widths: copy [] insert/dup widths 0 length? data/1 foreach line data [ forall line [ i: index? line widths/:i: max widths/:i length? line/1 ] ]

pad: func [n /local x][x: copy "" insert/dup x " " n x]

These formatting functions are passed as arguments to entable.

right: func [n s][rejoin [pad n - length? s s]]

left: func [n s][rejoin [s pad n - length? s]]

centre: func [n s /local h][ h: round/down (n - length? s) / 2 rejoin [pad h s pad n - h - length? s] ]

Display data as table.

entable: func [data format] [ foreach line data [ forall line [ prin rejoin [format pick widths index? line line/1 " "] ] print "" ] ]

Format data table.

foreach i [left centre right] [ print ["^/Align" i "...^/"] entable data get i] </lang>

Sample output:

Align left ...

Given      a          text       file   of     many      lines,     where    fields  within  a      line
are        delineated by         a      single 'dollar'  character, write    a       program
that       aligns     each       column of     fields    by         ensuring that    words   in     each
column     are        separated  by     at     least     one        space.
Further,   allow      for        each   word   in        a          column   to      be      either left
justified, right      justified, or     center justified within     its      column.

Align centre ...

  Given        a         text     file    of     many      lines,    where   fields  within    a    line
   are     delineated     by       a    single 'dollar'  character,  write      a    program
   that      aligns      each    column   of    fields       by     ensuring  that    words    in   each
  column      are     separated    by     at     least      one      space.
 Further,    allow       for      each   word     in         a       column    to      be    either left
justified,   right    justified,   or   center justified   within     its    column.

Align right ...

     Given          a       text   file     of      many     lines,    where  fields  within      a line
       are delineated         by      a single  'dollar' character,    write       a program
      that     aligns       each column     of    fields         by ensuring    that   words     in each
    column        are  separated     by     at     least        one   space.
  Further,      allow        for   each   word        in          a   column      to      be either left
justified,      right justified,     or center justified     within      its column.

REXX

version 1

<lang rexx> z.1 = "Given$a$text$file$of$many$lines,$where$fields$within$a$line$" z.2 = "are$delineated$by$a$single$'dollar'$character,$write$a$program" z.3 = "that$aligns$each$column$of$fields$by$ensuring$that$words$in$each$" z.4 = "column$are$separated$by$at$least$one$space." z.5 = "Further,$allow$for$each$word$in$a$column$to$be$either$left$" z.6 = "justified,$right$justified,$or$center$justified$within$its$column."

word. = "" width. = 0 maxcol = 0 do row = 1 to 6

 line = z.row
 do col = 1 by 1 until length(line) = 0
   parse var line word.row.col "$" line
   if length(word.row.col) > width.col then width.col = length(word.row.col)
 end
 if col > maxcol then maxcol = col

end

say "align left:" say do row = 1 to 6

 out = ""
 do col = 1 to maxcol
   out = out || left(word.row.col,width.col+1)
 end
 say out

end say say "align right:" say do row = 1 to 6

 out = ""
 do col = 1 to maxcol
   out = out || right(word.row.col,width.col+1)
 end
 say out

end say say "align center:" say do row = 1 to 6

 out = ""
 do col = 1 to maxcol
   out = out || center(word.row.col,width.col+1)
 end
 say out

end</lang>

version 2

<lang rexx> /*REXX program to display various alignments. */ cols=0; size=0; wid.=0; t.=; @.=

t.1="Given$a$text$file$of$many$lines,$where$fields$within$a$line$" t.2="are$delineated$by$a$single$'dollar'$character,$write$a$program" t.3="that$aligns$each$column$of$fields$by$ensuring$that$words$in$each$" t.4="column$are$separated$by$at$least$one$space." t.5="Further,$allow$for$each$word$in$a$column$to$be$either$left$" t.6="justified,$right$justified,$or$center$justified$within$its$column."

 do r=1 while t.r\==
 _=strip(t.r,,'$')
    do c=1 until _==
    parse var _ @.r.c '$' _
    wid.c=max(wid.c,length(@.r.c))
    end   /*c*/
 cols=max(cols,c)
 end      /*r*/

rows=r-1 /*adjust ROWS, it's 1 too big*/ do j=1 for cols; size=size+wid.j; end /*find width of biggest line.*/

 do j=1 for 3
 say; say center(word('left right center',j) "aligned",size+cols-1,"=")
   do r=1 for rows; _=
     do c=1 for cols;  x=@.r.c
     if j==1 then _=_   left(x,wid.c)
     if j==2 then _=_  right(x,wid.c)
     if j==3 then _=_ centre(x,wid.c)
     end   /*c*/
   say substr(_,2)
   end     /*r*/
 say
 end       /*j*/

</lang> Output:


==============================================left aligned==============================================
Given      a          text       file   of     many      lines,     where    fields  within  a      line
are        delineated by         a      single 'dollar'  character, write    a       program
that       aligns     each       column of     fields    by         ensuring that    words   in     each
column     are        separated  by     at     least     one        space.
Further,   allow      for        each   word   in        a          column   to      be      either left
justified, right      justified, or     center justified within     its      column.


=============================================right aligned==============================================
     Given          a       text   file     of      many     lines,    where  fields  within      a line
       are delineated         by      a single  'dollar' character,    write       a program
      that     aligns       each column     of    fields         by ensuring    that   words     in each
    column        are  separated     by     at     least        one   space.
  Further,      allow        for   each   word        in          a   column      to      be either left
justified,      right justified,     or center justified     within      its column.


=============================================center aligned=============================================
  Given        a         text     file    of     many      lines,    where   fields  within    a    line
   are     delineated     by       a    single 'dollar'  character,  write      a    program
   that      aligns      each    column   of    fields       by     ensuring  that    words    in   each
  column      are     separated    by     at     least      one      space.
 Further,    allow       for      each   word     in         a       column    to      be    either left
justified,   right    justified,   or   center justified   within     its    column.


version 3

Note: This version adds boxes around columns of output. <lang rexx> /*REXX program to display various alignments. */ cols=0; parse var cols size 1 wid. t. /*initializations.*/

t.1="Given$a$text$file$of$many$lines,$where$fields$within$a$line$" t.2="are$delineated$by$a$single$'dollar'$character,$write$a$program" t.3="that$aligns$each$column$of$fields$by$ensuring$that$words$in$each$" t.4="column$are$separated$by$at$least$one$space." t.5="Further,$allow$for$each$word$in$a$column$to$be$either$left$" t.6="justified,$right$justified,$or$center$justified$within$its$column."

 do r=1 while t.r\==
 t.r=translate(t.r,,'$')
    do c=1 until word(t.r,c)==
    wid.c=max(wid.c,length(word(t.r,c)))
    end
 cols=max(cols,c)
 end

rows=r-1 /*adjust ROWS, it's 1 too big*/ do j=1 for cols; size=size+wid.j; end /*find width of biggest line.*/

 do j=1 for 3
 say;say center(word('left right center',j) "aligned",size+cols,"=");say
   do r=0 to rows; _=
   !='|'; if r==0 then !='+'
     do c=1 for cols;
     x=word(t.r,c)
     if r==0 then x=copies("-",wid.c+1)
             else x=word(t.r,c)
     if j==1 then _=_||!||   left(x,wid.c)
     if j==2 then _=_||!||  right(x,wid.c)
     if j==3 then _=_||!|| centre(x,wid.c)
     end   /*c*/
   if r==0 then bot=_
   say _
   end     /*r*/
 say bot; say; say
 end       /*j*/

</lang> Output:


===============================================left aligned===============================================

+----------+----------+----------+------+------+---------+----------+--------+-------+-------+------+----+
|Given     |a         |text      |file  |of    |many     |lines,    |where   |fields |within |a     |line|
|are       |delineated|by        |a     |single|'dollar' |character,|write   |a      |program|      |    |
|that      |aligns    |each      |column|of    |fields   |by        |ensuring|that   |words  |in    |each|
|column    |are       |separated |by    |at    |least    |one       |space.  |       |       |      |    |
|Further,  |allow     |for       |each  |word  |in       |a         |column  |to     |be     |either|left|
|justified,|right     |justified,|or    |center|justified|within    |its     |column.|       |      |    |
+----------+----------+----------+------+------+---------+----------+--------+-------+-------+------+----+



==============================================right aligned===============================================

+----------+----------+----------+------+------+---------+----------+--------+-------+-------+------+----+
|     Given|         a|      text|  file|    of|     many|    lines,|   where| fields| within|     a|line|
|       are|delineated|        by|     a|single| 'dollar'|character,|   write|      a|program|      |    |
|      that|    aligns|      each|column|    of|   fields|        by|ensuring|   that|  words|    in|each|
|    column|       are| separated|    by|    at|    least|       one|  space.|       |       |      |    |
|  Further,|     allow|       for|  each|  word|       in|         a|  column|     to|     be|either|left|
|justified,|     right|justified,|    or|center|justified|    within|     its|column.|       |      |    |
+----------+----------+----------+------+------+---------+----------+--------+-------+-------+------+----+



==============================================center aligned==============================================

+----------+----------+----------+------+------+---------+----------+--------+-------+-------+------+----+
|  Given   |    a     |   text   | file |  of  |  many   |  lines,  | where  |fields |within |  a   |line|
|   are    |delineated|    by    |  a   |single|'dollar' |character,| write  |   a   |program|      |    |
|   that   |  aligns  |   each   |column|  of  | fields  |    by    |ensuring| that  | words |  in  |each|
|  column  |   are    |separated |  by  |  at  |  least  |   one    | space. |       |       |      |    |
| Further, |  allow   |   for    | each | word |   in    |    a     | column |  to   |  be   |either|left|
|justified,|  right   |justified,|  or  |center|justified|  within  |  its   |column.|       |      |    |
+----------+----------+----------+------+------+---------+----------+--------+-------+-------+------+----+


Ruby

<lang ruby>require 'stringio'

textinfile = <<END Given$a$text$file$of$many$lines,$where$fields$within$a$line$ are$delineated$by$a$single$'dollar'$character,$write$a$program that$aligns$each$column$of$fields$by$ensuring$that$words$in$each$ column$are$separated$by$at$least$one$space. Further,$allow$for$each$word$in$a$column$to$be$either$left$ justified,$right$justified,$or$center$justified$within$its$column. END

J2justifier = {'L' => String.instance_method(:ljust),

              'R' => String.instance_method(:rjust),
              'C' => String.instance_method(:center)}

=begin Justify columns of textual tabular input where the record separator is the newline and the field separator is a 'dollar' character. justification can be L, R, or C; (Left, Right, or Centered).

Return the justified output as a string =end def aligner(infile, justification = 'L')

 justifier = J2justifier[justification]

 fieldsbyrow = infile.map {|line| line.strip.split('$')}
 # pad to same number of fields per record
 maxfields = fieldsbyrow.map {|row| row.length}.max
 fieldsbyrow.map! {|row|
   row + []*(maxfields - row.length)
 }
 # calculate max fieldwidth per column
 colwidths = fieldsbyrow.transpose.map {|column|
   column.map {|field| field.length}.max
 }
 # pad fields in columns to colwidth with spaces
 fieldsbyrow.map! {|row|
   row.zip(colwidths).map {|field, width|
     justifier.bind(field)[width]
   }
 }

 fieldsbyrow.map {|row| row.join(" ")}.join("\n")

end

for align in %w{Left Right Center}

 infile = StringIO.new(textinfile)
 puts "\n# %s Column-aligned output:" % align
 puts aligner(infile, align[0..0])

end</lang>

Example output:

# Left Column-aligned output:
Given      a          text       file   of     many      lines,     where    fields  within  a      line
are        delineated by         a      single 'dollar'  character, write    a       program            
that       aligns     each       column of     fields    by         ensuring that    words   in     each
column     are        separated  by     at     least     one        space.                              
Further,   allow      for        each   word   in        a          column   to      be      either left
justified, right      justified, or     center justified within     its      column.                    

# Right Column-aligned output:
     Given          a       text   file     of      many     lines,    where  fields  within      a line
       are delineated         by      a single  'dollar' character,    write       a program            
      that     aligns       each column     of    fields         by ensuring    that   words     in each
    column        are  separated     by     at     least        one   space.                            
  Further,      allow        for   each   word        in          a   column      to      be either left
justified,      right justified,     or center justified     within      its column.                    

# Center Column-aligned output:
  Given        a         text     file    of     many      lines,    where   fields  within    a    line
   are     delineated     by       a    single 'dollar'  character,  write      a    program            
   that      aligns      each    column   of    fields       by     ensuring  that    words    in   each
  column      are     separated    by     at     least      one      space.                             
 Further,    allow       for      each   word     in         a       column    to      be    either left
justified,   right    justified,   or   center justified   within     its    column.                    

Scala

Works with: scala version 2.8.0.r18997-b20091009021954

For Scala 2.7, change from fromPath to fromFile, and remove the extra parameter to Source's getLines.

<lang scala>object ColumnAligner {

 val eol = System.getProperty("line.separator")
 def getLines(filename: String) = scala.io.Source.fromPath(filename).getLines(eol)
 def splitter(line: String) = line split '$'
 def getTable(filename: String) = getLines(filename) map splitter
 def fieldWidths(fields: Array[String]) = fields map (_ length)
 def columnWidths(txt: Iterator[Array[String]]) = (txt map fieldWidths).toList.transpose map (_ max)
 def alignField(alignment: Char)(width: Int)(field: String) = alignment match {
   case 'l' | 'L' => "%-"+width+"s" format field
   case 'r' | 'R' => "%"+width+"s" format field
   case 'c' | 'C' => val padding = (width - field.length) / 2; " "*padding+"%-"+(width-padding)+"s" format field
   case _ => throw new IllegalArgumentException
 }
 def align(aligners: List[String => String])(fields: Array[String]) =
   aligners zip fields map Function.tupled(_ apply _)
 
 def alignFile(filename: String, alignment: Char) = {
   def table = getTable(filename)
   val aligners = columnWidths(table) map alignField(alignment)
   table map align(aligners) map (_ mkString " ")
 }
 
 def printAlignedFile(filename: String, alignment: Char) {
   alignFile(filename, alignment) foreach println
 }

}</lang>

Another take:

<lang scala>def pad(s:String, i:Int, d:String) = {

 val padsize = (i-s.length).max(0)
 d match {
   case "left" => s+" "*padsize
   case "right" => " "*padsize+s
   case "center" => " "*(padsize/2) + s + " "*(padsize-padsize/2)
 }

}

val lines = scala.io.Source.fromFile("c:\\text.txt").getLines.map(_.trim()) val words = lines.map(_.split("\\$").toList).toList val lens = words.map(l => l.map(_.length)).toList

var maxlens = Map[Int,Int]() withDefaultValue 0 lens foreach (l =>

 for(i <- (0 until l.length)){
   maxlens += i -> l(i).max(maxlens(i))
 }

)

val padded = words map ( _.zipWithIndex.map{case(s,i)=>pad(s,maxlens(i),"center")+" "} ) padded map (_.reduceLeft(_ + _)) foreach println</lang>

Shiny

<lang shiny>text: 'Given$a$text$file$of$many$lines,$where$fields$within$a$line$ are$delineated$by$a$single$\'dollar\'$character,$write$a$program that$aligns$each$column$of$fields$by$ensuring$that$words$in$each$ column$are$separated$by$at$least$one$space. Further,$allow$for$each$word$in$a$column$to$be$either$left$ justified,$right$justified,$or$center$justified$within$its$column.'

align: action text; position;

   # split text into 2D array of lines and words
   lines : { for text.split ~\$?\r?\n~ { for a.split '$' a end } end }
   # calculate max required width for each column
   widths: { for lines for a here[b]: a.length.max here[b]? ends }
   spaces: action out ("%%%ds" in).format  end
   # formatting functions
   left: action word; width;
       pad: width-word.length
       print "%s%s " word spaces pad
   end
   right: action word; width;
       pad: width-word.length
       print "%s%s " spaces pad word
   end
   center: action word; width;
       pad: (width-word.length)/2
       print "%s%s%s " spaces pad.floor word spaces pad.ceil
   end
   if position.match ~^(left|center|right)$~ for lines
       for a local[position] a widths[b] end say 
   ends say 

end

align text 'left' align text 'center' align text 'right'</lang>

Given      a          text       file   of     many      lines,     where    fields  within  a      line 
are        delineated by         a      single 'dollar'  character, write    a       program 
that       aligns     each       column of     fields    by         ensuring that    words   in     each 
column     are        separated  by     at     least     one        space.   
Further,   allow      for        each   word   in        a          column   to      be      either left 
justified, right      justified, or     center justified within     its      column. 

  Given        a         text     file    of     many      lines,    where   fields  within    a    line 
   are     delineated     by       a    single 'dollar'  character,  write      a    program 
   that      aligns      each    column   of    fields       by     ensuring  that    words    in   each 
  column      are     separated    by     at     least      one      space.  
 Further,    allow       for      each   word     in         a       column    to      be    either left 
justified,   right    justified,   or   center justified   within     its    column. 

     Given          a       text   file     of      many     lines,    where  fields  within      a line 
       are delineated         by      a single  'dollar' character,    write       a program 
      that     aligns       each column     of    fields         by ensuring    that   words     in each 
    column        are  separated     by     at     least        one   space. 
  Further,      allow        for   each   word        in          a   column      to      be either left 
justified,      right justified,     or center justified     within      its column.

Tcl

<lang tcl>package require Tcl 8.5

set text {Given$a$text$file$of$many$lines,$where$fields$within$a$line$ are$delineated$by$a$single$'dollar'$character,$write$a$program that$aligns$each$column$of$fields$by$ensuring$that$words$in$each$ column$are$separated$by$at$least$one$space. Further,$allow$for$each$word$in$a$column$to$be$either$left$ justified,$right$justified,$or$center$justified$within$its$column.}

array set max {} foreach line [split $text \n] {

   set col 0
   set thisline [split $line \$]
   lappend words $thisline
   foreach word $thisline {
       set max([incr col]) [expr {[info exists max($col)]
                                   ? max($max($col), [string length $word])
                                   : [string length $word]
                           }]
   }

}

proc justify {word position width} {

   switch -exact -- $position {
       left {
           return [format "%-*s" $width $word]
       }
       center {
           set lpadw [expr {($width - [string length $word])/2}]
           return [format "%s%-*s" [string repeat " " $lpadw] [incr width -$lpadw] $word]
       }
       right {
           return [format "%*s" $width $word]
       }
   }

}

foreach position {left center right} {

   foreach thisline $words {
       set col 0
       set line ""
       foreach word $thisline {
           append line [justify $word $position $max([incr col])] " "
       }
       puts [string trimright $line]
   }
   puts ""

}</lang> Output:

Given      a          text       file   of     many      lines,     where    fields  within  a      line
are        delineated by         a      single 'dollar'  character, write    a       program
that       aligns     each       column of     fields    by         ensuring that    words   in     each
column     are        separated  by     at     least     one        space.
Further,   allow      for        each   word   in        a          column   to      be      either left
justified, right      justified, or     center justified within     its      column.

  Given        a         text     file    of     many      lines,    where   fields  within    a    line
   are     delineated     by       a    single 'dollar'  character,  write      a    program
   that      aligns      each    column   of    fields       by     ensuring  that    words    in   each
  column      are     separated    by     at     least      one      space.
 Further,    allow       for      each   word     in         a       column    to      be    either left
justified,   right    justified,   or   center justified   within     its    column.

     Given          a       text   file     of      many     lines,    where  fields  within      a line
       are delineated         by      a single  'dollar' character,    write       a program
      that     aligns       each column     of    fields         by ensuring    that   words     in each
    column        are  separated     by     at     least        one   space.
  Further,      allow        for   each   word        in          a   column      to      be either left
justified,      right justified,     or center justified     within      its column.

TUSCRIPT

<lang tuscript> $$ MODE TUSCRIPT MODE DATA $$ SET exampletext=* Given$a$text$file$of$many$lines,$where$fields$within$a$line$ are$delineated$by$a$single$'dollar'$character,$write$a$program that$aligns$each$column$of$fields$by$ensuring$that$words$in$each$ column$are$separated$by$at$least$one$space. Further,$allow$for$each$word$in$a$column$to$be$either$left$ justified,$right$justified,$or$center$justified$within$its$column. $$ MODE TUSCRIPT SET nix=SPLIT (exampletext,":$:",c1,c2,c3,c4,c5,c6,c7,c8,c9,c10,c11,c12) LOOP l1=1,12 SET colum=CONCAT ("c",l1) SET newcolum=CONCAT ("new",l1) SET @newcolum="", length=MAX LENGTH (@colum), space=length+2

LOOP n,l2=@colum
SET newcell=CENTER (l2,space)
SET @newcolum=APPEND (@newcolum,"~",newcell)
ENDLOOP
SET @newcolum=SPLIT  (@newcolum,":~:")

ENDLOOP SET exampletext=JOIN(new1,"$",new2,new3,new4,new5,new6,new7,new8,new9,new10,new11,new12) </lang> Output:

   Given    $     a      $    text    $  file  $   of   $   many    $   lines,   $  where   $ fields  $ within  $   a    $ line$ 
    are     $ delineated $     by     $   a    $ single $ 'dollar'  $ character, $  write   $    a    $ program $        $       
    that    $   aligns   $    each    $ column $   of   $  fields   $     by     $ ensuring $  that   $  words  $   in   $ each$ 
   column   $    are     $ separated  $   by   $   at   $   least   $    one     $  space.  $         $         $        $       
  Further,  $   allow    $    for     $  each  $  word  $    in     $     a      $  column  $   to    $   be    $ either $ left$ 
 justified, $   right    $ justified, $   or   $ center $ justified $   within   $   its    $ column. $         $        $       

Unix Shell

This is a draft implementation of the "align columns" problem using Unix shell commands. The key tool for left and right justified text is the "rs" command. Centered text is a little more complex, since this is not a feature currently in "rs" (The centered solution will be added later.) <lang bash> cat <<EOF_OUTER > just-nocenter.sh

  1. !/bin/sh

td() { cat <<'EOF' Given$a$text$file$of$many$lines,$where$fields$within$a$line$ are$delineated$by$a$single$'dollar'$character,$write$a$program that$aligns$each$column$of$fields$by$ensuring$that$words$in$each$ column$are$separated$by$at$least$one$space. Further,$allow$for$each$word$in$a$column$to$be$either$left$ justified,$right$justified,$or$center$justified$within$its$column. EOF }

rows=$( td | wc -l )

  1. get the number of fields

fields=$(td | rs -c'$' -g1 -h | awk '{print $2}')

  1. get the max of the value widths

cwidth=$(td | rs -c'$' -g1 -w1 2>/dev/null | awk 'BEGIN{w=0}{if(length>w){w=length}}END{print w}')

  1. compute the minimum line width for the columns

lwidth=$(( (1 + cwidth) * fields ))

  1. left adjusted columns

td | rs -c'$' -g1 -zn -w$lwidth

echo ""

  1. right adjusted columns

td | rs -c'$' -g1 -znj -w$lwidth

echo ""

exit EOF_OUTER </lang> Output: <lang sh> $ ./just-nocenter.sh Given a text file of many lines, where fields within a line are delineated by a single 'dollar' character, write a program that aligns each column of fields by ensuring that words in each column are separated by at least one space. Further, allow for each word in a column to be either left justified, right justified, or center justified within its column.

    Given          a       text   file     of      many     lines,    where  fields  within      a line
      are delineated         by      a single  'dollar' character,    write       a program            
     that     aligns       each column     of    fields         by ensuring    that   words     in each
   column        are  separated     by     at     least        one   space.                            
 Further,      allow        for   each   word        in          a   column      to      be either left

justified, right justified, or center justified within its column. </lang>

The centered output will be added later, when I've more time. I did this in about 10 minutes.

Ursala

The algorithm is to lex the text to a list of lists of strings assuming $ as a separator, then pad the lists out to the length of the maximum length list, transpose, do the same with each column, and transpose again. For left justification, nothing further but concatenation is needed. For right justification, each word's string of trailing blanks is moved to the beginning, and for center justification, the trailing blanks are divided equally between the beginning and end of each word. <lang Ursala>#import std

text =

-[Given$a$text$file$of$many$lines,$where$fields$within$a$line$ are$delineated$by$a$single$'dollar'$character,$write$a$program that$aligns$each$column$of$fields$by$ensuring$that$words$in$each$ column$are$separated$by$at$least$one$space. Further,$allow$for$each$word$in$a$column$to$be$either$left$ justified,$right$justified,$or$center$justified$within$its$column.]-

pad = sep`$*; @FS ~&rSSSK7+ (zipp` ^*D\~& leql$^)*rSSK7+ zipp0^*D/leql$^ ~&

just_left = mat` *+ pad just_right = mat` *+ pad; ==` ~-rlT** just_center = mat` *+ pad; ==` ~-rK30PlrK31PTT**

  1. show+

main = mat0 <.just_left,just_center,just_right> text</lang> output:

Given      a          text       file   of     many      lines,     where    fields  within  a      line
are        delineated by         a      single 'dollar'  character, write    a       program            
that       aligns     each       column of     fields    by         ensuring that    words   in     each
column     are        separated  by     at     least     one        space.                              
Further,   allow      for        each   word   in        a          column   to      be      either left
justified, right      justified, or     center justified within     its      column.                    

  Given        a         text     file    of     many      lines,    where   fields  within    a    line
   are     delineated     by       a    single 'dollar'  character,  write      a    program            
   that      aligns      each    column   of    fields       by     ensuring  that    words    in   each
  column      are     separated    by     at     least      one      space.                             
 Further,    allow       for      each   word     in         a       column    to      be    either left
justified,   right    justified,   or   center justified   within     its    column.                    

     Given          a       text   file     of      many     lines,    where  fields  within      a line
       are delineated         by      a single  'dollar' character,    write       a program            
      that     aligns       each column     of    fields         by ensuring    that   words     in each
    column        are  separated     by     at     least        one   space.                            
  Further,      allow        for   each   word        in          a   column      to      be either left
justified,      right justified,     or center justified     within      its column.                    

Vedit macro language

This implementation converts the file currently being edited. The file can then be saved with different filename if required. <lang vedit>RS(10, "$") // Field separator

  1. 11 = 1 // Align: 1 = left, 2 = center, 3 = right

// Reset column widths. Max 50 columns for (#1=40; #1<90; #1++) { #@1 = 0 }

// Find max width of each column BOF Repeat(ALL) {

   for (#1=40; #1<90; #1++) {
       Match(@10, ADVANCE)			// skip field separator if any

#2 = Cur_Pos Search("|{|@(10),|N}", NOERR) // field separator or end of line #3 = Cur_Pos - #2 // width of text if (#3 > #@1) { #@1 = #3 } if (At_EOL) { Break }

   }
   Line(1, ERRBREAK)

}

// Convert lines BOF Repeat(ALL) {

   for (#1=40; #1<90; #1++) {

#2 = Cur_Pos Search("|{|@(10),|N}", NOERR) if (At_EOL==0) { Del_Char(Chars_Matched) } #3 = #@1 - Cur_Pos + #2 // number of spaces to insert #4 = 0 if (#11 == 2) { #4 = #3/2; #3 -= #4 } // Center if (#11 == 3) { #4 = #3; #3 = 0 } // Right justify Set_Marker(1, Cur_Pos) Goto_Pos(#2) Ins_Char(' ', COUNT, #4) // add spaces before the word Goto_Pos(Marker(1)) Ins_Char(' ', COUNT, #3+1) // add spaces after the word if (At_EOL) { Break }

   }
   Line(1, ERRBREAK)

}</lang>

Example output: <lang vedit>-- Left: Given a text file of many lines, where fields within a line are delineated by a single 'dollar' character, write a program that aligns each column of fields by ensuring that words in each column are separated by at least one space. Further, allow for each word in a column to be either left justified, right justified, or center justified within its column.

-- Center:

 Given        a         text     file    of     many      lines,    where   fields  within    a    line 
  are     delineated     by       a    single 'dollar'  character,  write      a    program 
  that      aligns      each    column   of    fields       by     ensuring  that    words    in   each 
 column      are     separated    by     at     least      one      space.  
Further,    allow       for      each   word     in         a       column    to      be    either left 

justified, right justified, or center justified within its column.

-- Right:

    Given          a       text   file     of      many     lines,    where  fields  within      a line 
      are delineated         by      a single  'dollar' character,    write       a program 
     that     aligns       each column     of    fields         by ensuring    that   words     in each 
   column        are  separated     by     at     least        one   space. 
 Further,      allow        for   each   word        in          a   column      to      be either left 

justified, right justified, or center justified within its column.</lang>