Rob van der Woude's Scripting Pages

Batch How To ...

Align text to display as tables

Aligning text in tables in the console may sometimes prove quite a challenge.
The first and easiest way you should try, of course, is using tabs:

first	1
next	2
last	3

In this case, it works, because the texts in the first column are of almost equal length.
But what if they aren't?

fire truck	1
bicycle	2
pedestrian	3

As you can see in the above example, the numbers are no longer properly aligned in the second column, because the text lengths in the first column differ more than a tab can compensate for.
The way to go would be padding the texts in the first column with spaces until they are all of equal length.

fire truck    1
bicycle       2
pedestrian    3
Note: Hover the mouse pointer over the whitespace in the tables above to see the number of tabs or spaces required to align this text as a table.

How to do this in batch

Let's take this list of Beatles' song titles from a file named songs.txt:

A Day In The Life
All You Need Is Love
And Your Bird Can Sing
Dear Prudence
Girl
Hey Bulldog
Hey Jude
In My Life
Lady Madonna
Let It Be
Lucy In The Sky With Diamonds
Michelle
Nowhere Man
Ob-La-Di- Ob-La-Da
Penny Lane
Run For Your Life
Sgt Pepper's Lonely Hearts Club Band
Strawberry Fields Forever
The Fool On The Hill
With A Little Help From My Friends
Yesterday

Now, with batch code, let's create a table with the song titles in the first column, and the artists (The Beatles in this case) in the second column.
With just tabs, the code is simple:

@ECHO OFF
FOR /F "tokens=*" %%A IN (songs.txt) DO (
	REM %%A is followed by a single tab and then 'The Beatles'
	ECHO.%%A	The Beatles
)

but the output is a mess:

A Day In The Life	The Beatles
All You Need Is Love	The Beatles
And Your Bird Can Sing	The Beatles
Dear Prudence	The Beatles
Girl	The Beatles
Hey Bulldog	The Beatles
Hey Jude	The Beatles
In My Life	The Beatles
Lady Madonna	The Beatles
Let It Be	The Beatles
Lucy In The Sky With Diamonds	The Beatles
Michelle	The Beatles
Nowhere Man	The Beatles
Ob-La-Di- Ob-La-Da	The Beatles
Penny Lane	The Beatles
Run For Your Life	The Beatles
Sgt Pepper's Lonely Hearts Club Band	The Beatles
Strawberry Fields Forever	The Beatles
The Fool On The Hill	The Beatles
With A Little Help From My Friends	The Beatles
Yesterday	The Beatles

Appending 40 spaces to each title and then truncating the result at 40 characters looks a lot better:

@ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
:: The equal sign is followed by 40 spaces and a doublequote
SET "FortySpaces=                                        "
FOR /F "tokens=*" %%A IN (songs.txt) DO (
	REM Variable 'Line' contains one line, i.e. one complete title
	SET Line=%%A
	REM Append 40 spaces to the title
	SET Line=!Line!%FortySpaces%
	REM Truncate title plus spaces at 40 characters
	SET Line=!Line:~0,40!
	REM Append the artist name
	SET Line=!Line!    The Beatles
	REM Display the result
	ECHO.!Line!
)
ENDLOCAL

This is the output of the batch code:

A Day In The Life                           The Beatles
All You Need Is Love                        The Beatles
And Your Bird Can Sing                      The Beatles
Dear Prudence                               The Beatles
Girl                                        The Beatles
Hey Bulldog                                 The Beatles
Hey Jude                                    The Beatles
In My Life                                  The Beatles
Lady Madonna                                The Beatles
Let It Be                                   The Beatles
Lucy In The Sky With Diamonds               The Beatles
Michelle                                    The Beatles
Nowhere Man                                 The Beatles
Ob-La-Di- Ob-La-Da                          The Beatles
Penny Lane                                  The Beatles
Run For Your Life                           The Beatles
Sgt Pepper's Lonely Hearts Club Band        The Beatles
Strawberry Fields Forever                   The Beatles
The Fool On The Hill                        The Beatles
With A Little Help From My Friends          The Beatles
Yesterday                                   The Beatles

Close enough for now!

Had we chosen 30 characters instead of 40 for the first column, some titles would have been chopped:

A Day In The Life                 The Beatles
All You Need Is Love              The Beatles
And Your Bird Can Sing            The Beatles
Dear Prudence                     The Beatles
Girl                              The Beatles
Hey Bulldog                       The Beatles
Hey Jude                          The Beatles
In My Life                        The Beatles
Lady Madonna                      The Beatles
Let It Be                         The Beatles
Lucy In The Sky With Diamonds     The Beatles
Michelle                          The Beatles
Nowhere Man                       The Beatles
Ob-La-Di- Ob-La-Da                The Beatles
Penny Lane                        The Beatles
Run For Your Life                 The Beatles
Sgt Pepper's Lonely Hearts Clu    The Beatles
Strawberry Fields Forever         The Beatles
The Fool On The Hill              The Beatles
With A Little Help From My Fri    The Beatles
Yesterday                         The Beatles

With 50 or even more characters for the first column, the whitespace between columns would have been too wide.
So if you don't know what text to expect in the first column, how do you make it just wide enough?
This will require some code to determine string lengths.
For long strings, or strings of unknown length, you can use Dave Benham's rather complex "successive approximation" approach; this will work for any string of any length.
For text alignment in the console, however, we usually won't have to deal with string of over 80 characters, so we can use the simpler "brute force" approach demonstrated in the GetMaxStringLength subroutine below:

@ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
:: First iterate through the list to find the length of the longest title
SET ColumnWidth=0
FOR /F "tokens=*" %%A IN (songs.txt) DO (
	CALL :GetMaxStringLength ColumnWidth "%%~A"
)
:: The equal sign is followed by 80 spaces and a doublequote
SET "EightySpaces=                                                                                "
FOR /F "tokens=*" %%A IN (songs.txt) DO (
	REM Append 80 spaces after song title
	SET Column=%%A%EightySpaces%
	REM Chop at maximum column width, using a FOR loop
	REM as a kind of "super delayed" variable expansion
	FOR %%W IN (!ColumnWidth!) DO SET Column=!Column:~0,%%W!
	REM Append artist name and display the result
	ECHO.!Column!    The Beatles
)
ENDLOCAL
GOTO:EOF

:GetMaxStringLength
:: Usage : GetMaxStringLength OutVariableName StringToBeMeasured
:: Note  : OutVariable may already have an initial value
SET StrTest=%~2
:: Just add zero, in case the initial value is empty
SET /A %1 += 0
:: Maximum length we will allow, modify appended spaces accordingly
SET MaxLength=80
IF %MaxLength% GTR !%1! (
	FOR /L %%A IN (!%1!,1,%MaxLength%) DO (
		IF NOT "!StrTest:~%%A!"=="" (
			SET /A %1 = %%A + 1
		)
	)
)
GOTO:EOF

Much more complex code, but a much more satisfying result:

A Day In The Life                       The Beatles
All You Need Is Love                    The Beatles
And Your Bird Can Sing                  The Beatles
Dear Prudence                           The Beatles
Girl                                    The Beatles
Hey Bulldog                             The Beatles
Hey Jude                                The Beatles
In My Life                              The Beatles
Lady Madonna                            The Beatles
Let It Be                               The Beatles
Lucy In The Sky With Diamonds           The Beatles
Michelle                                The Beatles
Nowhere Man                             The Beatles
Ob-La-Di- Ob-La-Da                      The Beatles
Penny Lane                              The Beatles
Run For Your Life                       The Beatles
Sgt Pepper's Lonely Hearts Club Band    The Beatles
Strawberry Fields Forever               The Beatles
The Fool On The Hill                    The Beatles
With A Little Help From My Friends      The Beatles
Yesterday                               The Beatles
Notes: [1] You may want to limit the first column's width (variable MaxLength) to allow some room for column 2 within the console's limited width.
  [2] In English Windows versions, use the following command to determine the total available width for the columns:

FOR /F "tokens=2 delims=:" %%A IN ('MODE CON ^| FIND "Columns"') DO SET ConsoleWidth=%%A

page last modified: 2022-03-01