Table Formatting

Many text files contain tabular data. Unfortunately, getting the columns to line up can prove difficult. For example, here is a typical file:

/dev/cdrom /mnt/cdrom iso9660 user,unhide,ro 0 0 
/dev/scd1 /mnt/cdrom1 iso9660 noauto,unhide,user,ro 0 0 
/dev/scd0 /mnt/cdrom2 iso9660 noauto,unhide,user,ro 0 0 
/dev/loop0 /mnt/cdrom_l iso9660 noauto,unhide,user,ro 0 0 
/dev/sda1 /mnt/optical ext2 defaults,noauto,user 0 0

It would be nice to see something like this:

/dev/cdrom /mnt/cdrom   iso9660 user,unhide,ro        0 0 
/dev/scd1  /mnt/cdrom1  iso9660 noauto,unhide,user,ro 0 0 
/dev/scd0  /mnt/cdrom2  iso9660 noauto,unhide,user,ro 0 0 
/dev/loop0 /mnt/cdrom_l iso9660 noauto,unhide,user,ro 0 0 
/dev/sda1  /mnt/optical ext2    defaults,noauto,user  0 0

You can write a Perl program to process this text and make it look pretty. Start by reading in the data and dividing it up into words:

28    while (<>) {
29        chomp($_); 
30        my @words = split /s+/, $_; 
31        push (@lines, [@words]); 
32    }

This example uses the magic Perl file <>, which goes through all the arguments on the command line. The result is an array called @lines in which each element is a line from the input.

The actual element is not stored as a string but rather as an array of words.

Next, this data structure is processed to determine which line has the most words on it:

37    my $n_fields = 0; 
38 
39    foreach my $cur_line (@lines) {
40        if ($#$cur_line > $n_fields) {
41            $n_fields = $#$cur_line; 
42        } 
43    }

Now you can go through and compute the size of each field:

48    my @field_size = (); 
49    for (my $cur_field = 0; 
50            $cur_field <= $n_fields; 
51            $cur_field++) {
52 
53        $field_size[$cur_field] = 0; 
54        foreach my $cur_line (@lines) {
55            if (not defined($cur_line–>[$cur_field])) {
56                next; 
57            } 
58            if (length($cur_line–>[$cur_field]) > 
59                    $field_size[$cur_field]) {
60                $field_size[$cur_field] = 
61                    length($cur_line–>[$cur_field]); 
62            } 
63        } 
64    }

You’re almost there. You need to create a format string that can be used for printing the table:

69    my $format = ""; 
70    foreach my $cur_field (@field_size) {
71        if ($format ne "") {
72            $format .= " "; 
73        } 
74        $format .= "%–${cur_field}s"; 
75    } 
76    $format .= "
";

Finally, there’s nothing left to do but print it:

81    foreach my $cur_line (@lines) {
82        printf $format, @$cur_line; 
83    }

The result is a beautifully formatted table. The entire program is presented in Listing 16.6.

Listing 16.6. table.pl
 1    =pod 
 2 
 3    =head1 NAME 
 4 
 5    table.pl – Print out tables nicely formatted 
 6 
 7    =head1 SYNOPSIS 
 8 
 9        table.pl <file> [<file> ....] 
10 
11    =head1 DESCRIPTION 
12 
13    The I<table.pl> examines the input files which are assumed to contain 
14    data in columns and prints them nicely.  In other words, it makes 
15    the tables look nice. 
16 
17    =cut 
18    use strict; 
19    use warnings; 
20 
21 
22    # The input as lines, then as columns 
23    my @lines = (); 
24 
25    # 
26    # Grab input, break apart into fields 
27    # 
28    while (<>) {
29        chomp($_); 
30        my @words = split /s+/, $_; 
31        push (@lines, [@words]); 
32    } 
33 
34    # 
35    # Find out how many fields there are 
36    # 
37    my $n_fields = 0; 
38 
39    foreach my $cur_line (@lines) {
40        if ($#$cur_line > $n_fields) {
41            $n_fields = $#$cur_line; 
42        } 
43    } 
44 
45    # 
46    # Find the size of each field. 
47    # 
48    my @field_size = (); 
49    for (my $cur_field = 0; 
50            $cur_field <= $n_fields; 
51            $cur_field++) {
52 
53        $field_size[$cur_field] = 0; 
54        foreach my $cur_line (@lines) {
55            if (not defined($cur_line–>[$cur_field])) {
56                next; 
57            } 
58            if (length($cur_line–>[$cur_field]) > 
59                    $field_size[$cur_field]) {
60                $field_size[$cur_field] = 
61                    length($cur_line–>[$cur_field]); 
62            } 
63        } 
64    } 
65 
66    # 
67    # Build the printing format 
68    # 
69    my $format = ""; 
70    foreach my $cur_field (@field_size) {
71        if ($format ne "") {
72            $format .= " "; 
73        } 
74        $format .= "%–${cur_field}s"; 
75    } 
76    $format .= "
"; 
77 
78    # 
79    # Print 
80    # 
81    foreach my $cur_line (@lines) {
82        printf $format, @$cur_line; 
83    } 
84

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset