Task: Align columns




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") {
        words := strings.Split(line, "$")
        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)
}







Fortran:       SUBROUTINE RAKE(IN,M,X,WAY)	
Collates column widths so that each column is wide enough for its widest member.
       INTEGER IN		
       INTEGER M		
       CHARACTER*1 X		
       INTEGER WAY		
       INTEGER W(M + 1)		
       INTEGER C(0:M + 1)	
       CHARACTER*(M) ACARD	
       CHARACTER*(28 + 4*M) FORMAT	
       INTEGER I		
       INTEGER L,LF		
       INTEGER NF,MF		
       CHARACTER*6 WAYNESS(-1:+1)	
       PARAMETER (WAYNESS = (/"Left","Centre","Right"/))	
       INTEGER LINPR	
       COMMON LINPR	
        W = 0		
        MF = 0		
        C(0) = 0	
        WRITE (LINPR,*)	
        WRITE (LINPR,*) "Align ",WAYNESS(MIN(MAX(WAY,-1),+1))	

Chase through the file assessing the lengths of each field.
   10   READ (IN,11,END = 20) L,ACARD(1:L)	
   11   FORMAT (Q,A)				
        CALL LIZZIEBORDEN	
        W(1:NF) = MAX(W(1:NF),C(1:NF) - C(0:NF - 1) - 1)	
        MF = MAX(MF,NF)		
        GO TO 10		

Concoct a FORMAT based on the maximum size of each field. Plus one.
   20   REWIND(IN)		
        WRITE (FORMAT,21) W(1:MF) + 1	
   21   FORMAT ("(",<MF>("A",I0,","))	
        LF = INDEX(FORMAT,", ")		
        IF (LF.LE.0) STOP "Format trouble
        FORMAT(LF:LF) = ")"			
        WRITE (LINPR,*) "Format",FORMAT(1:LF)	

Chug afresh, this time knowing the maximum length of each field.
   30   READ (IN,11,END = 40) L,ACARD(1:L)	
        CALL LIZZIEBORDEN		
        SELECT CASE(WAY)	
         CASE(-1)		
          WRITE (LINPR,FORMAT) (ACARD(C(I - 1) + 1:C(I) - 1)//	
     1     REPEAT(" ",W(I) - C(I) + C(I - 1) + 1),I = 1,NF)	
         CASE( 0)		
          WRITE (LINPR,FORMAT) (ACARD(C(I - 1) + 1:C(I) - 1)//	
     1     REPEAT(" ",(W(I) - C(I) + C(I - 1) + 1)/2),I = 1,NF)	
         CASE(+1)		
          WRITE (LINPR,FORMAT) (ACARD(C(I - 1) + 1:C(I) - 1),I = 1,NF)	
         CASE DEFAULT		
         WRITE (LINPR,*) "Huh? WAY=",WAY	
         STOP "Unanticipated value for WAY
        END SELECT		
        GO TO 30		
Closedown
   40   REWIND(IN)		
       CONTAINS	
        SUBROUTINE LIZZIEBORDEN	
          NF = 0		
          DO I = 1,L		
            IF (ICHAR(ACARD(I:I)).EQ.ICHAR(X)) THEN	
              NF = NF + 1		
              C(NF) = I		
            END IF		
          END DO		
          NF = NF + 1		
          C(NF) = L + 1		
        END SUBROUTINE LIZZIEBORDEN	
      END SUBROUTINE RAKE	

      INTEGER L,M,N	
      INTEGER LINPR,IN	
      COMMON LINPR	
      LINPR = 6		
      IN = 10		
      OPEN (IN,FILE="Rake.txt",STATUS="OLD",ACTION="READ")	
      N = 0		
      M = 0		

    1 READ (IN,2,END = 10) L	
    2 FORMAT (Q)	
      N = N + 1		
      M = MAX(M,L)	
      GO TO 1		

   10 REWIND (IN)	
      WRITE (LINPR,*) N,"Recs, longest rec. length is ",M
      CALL RAKE(IN,M,"$",-1)	
      CALL RAKE(IN,M,"$", 0)	
      CALL RAKE(IN,M,"$",+1)	
      END