Some of Sunday's edits have been lost. The edits from Saturday that were reverted have been restored. Site is now hosted on prgmr.com. Thank you for your patience. This notice will be removed one week from posting. --Michael Mol 18:12, 7 March 2010 (UTC)

Align columns

From Rosetta Code

Jump to: navigation, search
Align columns is a programming task. Visitors like you are encouraged to solve it according to the task description, using any language they may happen to know.
Add to BlogMarksAdd to del.icio.usAdd to diggAdd to NewsvineAdd to redditAdd to Slashdot

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.

Contents

[edit] Ada

Library: Simple components for 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;

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. 

[edit] 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

[edit] 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))
}

[edit] 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 ""
}
}

[edit] C

See Column Aligner/C

[edit] C++

See Column Aligner/C++

[edit] C#

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= new string[] {
"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.",
};
 
string[] output = AlignColumns(input, JustifyCenter);
}
}

[edit] Common 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))

[edit] D

This example allows selection of right- and left-favoring center alignments, defaulting to left-favoring center alignment.

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);
}
}
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.

[edit] 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"
}
}
? 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.

[edit] 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 ;
example-text { +left+ +middle+ +right+ } [ print-aligned ] with each

[edit] Groovy

Solution:

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() }
}

Test Program:

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()
}

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.

[edit] 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)

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.

[edit] J

Solution

'LEFT CENTER RIGHT'=: i.3   NB. to specify justification
 
NB.* alignCols v Format delimited text in justified columns
NB. result: literal table
NB. y is: literal list to format, fields delimited by $
NB. x is: optionally specify justification. Default is LEFT
alignCols=: verb define
LEFT alignCols y NB. specify default left argument where none given
:
currboxchars=. 9!:6 '' NB. store current settings so can restore later
currboxalign=. 9!:16 ''
(9!:7) 11$' ' NB. set list of box characters to spaces
9!:17 ,~ x NB. set box alignment
res=. _2{:\ ": <;._2 @:(,&'$');._2 y NB. parse & format text
9!:17 currboxalign NB. restore settings
9!:7 currboxchars
res NB. return result
)

Example:

   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.

[edit] 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){var init=this.toString(),r=init;if(n==0) return "";if(n<2) return init;n--;while(n--){r+=init;};return r}
 
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)


[edit] 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.


[edit] 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);
;;

[edit] 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}

[edit] 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 ;
################################################################## ####
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" ;
}

a shorter solution

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

[edit] 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);
 
?>

[edit] 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

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.                     

[edit] 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;
 


[edit] PureBasic

Works with: PureBasic version 4.41

When compiled for Windows x86, this program is only 8 kB.

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

[edit] 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])

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.                     

[edit] 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)
 
#Split words by the dollar
words <- strsplit(lines, "\\$")
 
#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")
 
# Print
print0 <- function(x) invisible(apply(x, 1, function(x) cat(x, "\n")))
print0(leftjust)
print0(rightjust)
print0(centrejust)

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.                                  

[edit] 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

[edit] 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

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.                    

[edit] 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.

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
}
}

Another take:

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

[edit] 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 ""
}

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.

[edit] 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.)

 
cat <<EOF_OUTER > just-nocenter.sh
#!/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 )
 
# get the number of fields
fields=$(td | rs -c'$' -g1 -h | awk '{print $2}')
 
# 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}')
 
# compute the minimum line width for the columns
lwidth=$(( (1 + cwidth) * fields ))
 
# left adjusted columns
td | rs -c'$' -g1 -zn -w$lwidth
 
echo ""
 
# right adjusted columns
td | rs -c'$' -g1 -znj -w$lwidth
 
echo ""
 
exit
EOF_OUTER
 

Output:

 
$ ./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.
 

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

[edit] 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.

#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**
 
#show+
 
main = mat0 <.just_left,just_center,just_right> text

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.                    

[edit] Vedit macro language

This implementation converts the file currently being edited. The file can then be saved with different filename if required.

RS(10, "$")		// Field separator
#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)
}

Example output:

-- 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.
Personal tools
Google AdSense