formating pipe delimited file

J

J

I have a file with 40000 lines. Each line is a row of data, and the fields
are seperated by pipes ( | ). I would like to align all pipes so that the
fields will line up.

example:

field1 | 100 | 1 | | |
field2islong| | example | | 3 |

would become

field1 | 100 | 1 | | |
field2islong| | example | | 3 |


anyone have any ideas.

J
 
J

J. Gleixner

J said:
I have a file with 40000 lines. Each line is a row of data, and the fields
are seperated by pipes ( | ). I would like to align all pipes so that the
fields will line up.

example:

field1 | 100 | 1 | | |
field2islong| | example | | 3 |

would become

field1 | 100 | 1 | | |
field2islong| | example | | 3 |


anyone have any ideas.

J

split each line, find the maximun length for each column, then use
printf with the max length of each column.
 
B

Bob Walton

J said:
I have a file with 40000 lines. Each line is a row of data, and the fields
are seperated by pipes ( | ). I would like to align all pipes so that the
fields will line up. ....
J

Do you know any information on field lengths up front? If not, you'll
have to pass through your data once to determine the maximum length of
each field, then pass through it again to output it. The actual program
to do that is trivial. The "x" operator would be useful in it.

You will have to decide if you want to read the entire file to memory
the first time through (I don't know what 40000 lines translates to in
bytes, or what that number of bytes means to your computer system), or
whether the file should be read twice.
 
B

Ben Morrow

J said:
I have a file with 40000 lines. Each line is a row of data, and the fields
are seperated by pipes ( | ). I would like to align all pipes so that the
fields will line up.

example:

field1 | 100 | 1 | | |
field2islong| | example | | 3 |

would become

field1 | 100 | 1 | | |
field2islong| | example | | 3 |


anyone have any ideas.

(untested)

use Fcntl qw/:seek/;

{
open my $FILE, '<', $file or die "can't open $file: $!";
my @lengths;

while (<$FILE>) {
my @f = split /\|/;
for (0..$#f) {
$lengths[$_] < length $f[$_]
and $lengths[$_] = length $f[$_];
}
}

my $fmt = join '|', map "%-$_s", @lengths;

seek $FILE, 0, SEEK_SET;

{
open my $OUT, '>', "$file.new"
or die "can't create $file.new: $!";

local $\ = "\n";
# or maybe "|\n", if the last field is really null

while (<$FILE>) {
print $OUT sprintf $fmt => split /\|/;
}
}
}

rename "$file.new", $file or die "can't overwrite $file: $!";
 
J

John W. Krahn

J said:
I have a file with 40000 lines. Each line is a row of data, and the fields
are seperated by pipes ( | ). I would like to align all pipes so that the
fields will line up.

example:

field1 | 100 | 1 | | |
field2islong| | example | | 3 |

would become

field1 | 100 | 1 | | |
field2islong| | example | | 3 |

anyone have any ideas.

Something like this should work:

#!/usr/bin/perl
use warnings;
use strict;

( $^I, @ARGV ) = ( '.bak', 'yourfile.txt' );

my @lens = map length, split /\|/, <>, -1;
while ( <> ) {
chomp;
my $i = -1;
$lens[ ++$i ] < $_ and $lens[ $i ] = $_ for map length, split /\|/, $_, -1;
}
@ARGV = $ARGV;
while ( <> ) {
chomp;
my $i;
print join( '|', map sprintf( '%-*s', $lens[ $i++ ], $_ ), split /\|/, $_, -1 ), "\n";
}

__END__



John
 
A

Anno Siegel

J said:
I have a file with 40000 lines. Each line is a row of data, and the fields
are seperated by pipes ( | ). I would like to align all pipes so that the
fields will line up.

example:

field1 | 100 | 1 | | |
field2islong| | example | | 3 |

would become

field1 | 100 | 1 | | |
field2islong| | example | | 3 |

Ah... an alignment problem. That's an occasion to plug Text::Table :)

use Text::Table;

# Define a table with 5 columns, untitled, with "|" as column separators
my $tb = Text::Table->new( ('', \ '|') x 5);

# Fill in the data lines
$tb->add( split /\|/) while <DATA>;

# print the re-formatted lines
print $tb;

__DATA__
field1 | 100 | 1 | | |
field2islong| | example | | 3 |


Anno
 
J

J

J wrote:

Something like this should work:

#!/usr/bin/perl
use warnings;
use strict;

( $^I, @ARGV ) = ( '.bak', 'yourfile.txt' );

my @lens = map length, split /\|/, <>, -1;
while ( <> ) {
chomp;
my $i = -1;
$lens[ ++$i ] < $_ and $lens[ $i ] = $_ for map length, split /\|/, $_,
-1;
}
@ARGV = $ARGV;
while ( <> ) {
chomp;
my $i;
print join( '|', map sprintf( '%-*s', $lens[ $i++ ], $_ ), split /\|/,
$_, -1 ), "\n";
}

__END__


I'm having a hard time understand this line of code
$lens[ ++$i ] < $_ and $lens[ $i ] = $_ for map length, split /\|/, $_,-1

Could some one explain this line of code.

John
 
J

John W. Krahn

J said:
J wrote:

Something like this should work:

#!/usr/bin/perl
use warnings;
use strict;

( $^I, @ARGV ) = ( '.bak', 'yourfile.txt' );

my @lens = map length, split /\|/, <>, -1;
while ( <> ) {
chomp;
my $i = -1;
$lens[ ++$i ] < $_ and $lens[ $i ] = $_ for map length, split /\|/, $_,
-1;
}
@ARGV = $ARGV;
while ( <> ) {
chomp;
my $i;
print join( '|', map sprintf( '%-*s', $lens[ $i++ ], $_ ), split /\|/,
$_, -1 ), "\n";
}

__END__

I'm having a hard time understand this line of code
$lens[ ++$i ] < $_ and $lens[ $i ] = $_ for map length, split /\|/, $_,-1

Could some one explain this line of code.

Sure, to put it more verbosely:

# set $index to -1 because we pre-increment it in the loop
my $index = -1;

# split the line in $_ using the pipe '|' character
# third argument is -1 to get trailing empty fields
for my $field ( split /\|/, $_, -1 ) {

my $length = length $field;

++$index;

if ( $lens[ $index ] < $length ) {

# store $length in the array @lens if it is
# greater than the previous value in @lens
$lens[ $index ] = $length;
}
}



John
 
J

J

J said:
J wrote:

Something like this should work:

#!/usr/bin/perl
use warnings;
use strict;

( $^I, @ARGV ) = ( '.bak', 'yourfile.txt' );

my @lens = map length, split /\|/, <>, -1;
while ( <> ) {
chomp;
my $i = -1;
$lens[ ++$i ] < $_ and $lens[ $i ] = $_ for map length, split /\|/, $_,
-1;
}
@ARGV = $ARGV;
while ( <> ) {
chomp;
my $i;
print join( '|', map sprintf( '%-*s', $lens[ $i++ ], $_ ), split /\|/,
$_, -1 ), "\n";
}

__END__

I'm having a hard time understand this line of code
$lens[ ++$i ] < $_ and $lens[ $i ] = $_ for map length, split /\|/, $_,-1

Could some one explain this line of code.

Sure, to put it more verbosely:

# set $index to -1 because we pre-increment it in the loop
my $index = -1;

# split the line in $_ using the pipe '|' character
# third argument is -1 to get trailing empty fields
for my $field ( split /\|/, $_, -1 ) {

my $length = length $field;

++$index;

if ( $lens[ $index ] < $length ) {

# store $length in the array @lens if it is
# greater than the previous value in @lens
$lens[ $index ] = $length;
}
}



John

I understand a little bit better. That is the hardest thing about perl for
me, is understanding all the shortcut codes.

Thanks for explaining stuff to me.

J
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,266
Messages
2,571,087
Members
48,773
Latest member
Kaybee

Latest Threads

Top