Align columns: Difference between revisions

From Rosetta Code
Content added Content deleted
(→‎{{header|ALGOL 68}}: Ada solution added)
Line 14: Line 14:
Further,$allow$for$each$word$in$a$column$to$be$either$left$
Further,$allow$for$each$word$in$a$column$to$be$either$left$
justified,$right$justified,$or$center$justified$within$its$column.</pre>
justified,$right$justified,$or$center$justified$within$its$column.</pre>
=={{header|Ada}}==
{{libheader|Simple components for Ada}}
<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;
</ada>
Formatted file sample:
<pre style="height:15ex;overflow:scroll">
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.
</pre>
=={{header|ALGOL 68}}==
=={{header|ALGOL 68}}==
<pre>
<pre>
Line 82: Line 172:
OD
OD
END</pre>
END</pre>

=={{header|OCaml}}==
=={{header|OCaml}}==
<ocaml>#load "str.cma"
<ocaml>#load "str.cma"

Revision as of 20:04, 17 November 2008

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.

Ada

<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; </ada> 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

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

OCaml

<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);
</ocaml>

Python

<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 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
 
 assert justification in 'LRC', "justification can be L, R, or C; (Left, Right, or Centered)."
 justifier = j2justifier[justification]
 
 fieldsbyrecord= [line.strip().split('$') for line in infile]
 # pad to same number of fields per record
 maxfields = max(len(record) for record in fieldsbyrecord)
 fieldsbyrecord = [fields + []*(maxfields - len(fields))
                   for fields in fieldsbyrecord]
 # rotate
 fieldsbycolumn = zip(*fieldsbyrecord)
 # 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
 fieldsbyrecord = zip(*fieldsbycolumn)
 return "\n".join( " ".join(record) for record in fieldsbyrecord)


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

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

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.