rpinnam has asked for the wisdom of the Perl Monks concerning the following question:

I have a input pipe delimiter file as:
IFB Northpole||| Alaska||| 907-555-5555 Walmart||| Fairbanks||| Alaska Chicken||| Anchorage||| Alaska||| 907-555-5555 Beef||| Somewhere|||||Over the Rainbow|||907-555-5555
I want my output to be :
IFB Northpole| Alaska| 907-555-5555| Walmart| Fairbanks| Alaska Chicken| Anchorage| Alaska| 907-555-5555 Beef| Somewhere|Over the Rainbow|907-555-5555
Here is my code :
#!/usr/bin/perl @FILES = glob("*.txt"); foreach my $file (@FILES) { open my $fh, '<', $file; (my $fileName = $file) =~ s/\.[^.]+$//; open(my $output, '>', $fileName.".csv") or die "Could not open fil +e '$fileName' $!"; my @category; my @Detail; print $output ""; while (my $line = <$fh>) { chomp $line; @tokens = split /\|/, $line; chomp(@tokens); $objectName=$tokens[0]; if($objectName ne ""){ my @objectFields; $size = scalar(@tokens); @tokens = @tokens[1..$size]; foreach my $token (@tokens){ $token =~ s/\r|\n//g; push @objectFields,$token; } if($objectName eq "IFB Northpole"){ @Detail=@objectFields; }elsif($objectName eq "Walmart"){ @category=@objectFields; }elsif($objectName eq "Chicken"){ @category=@objectFields; }elsif($objectName eq "Beef"){ my @item = (@Detail,@category,@objectFields); print $output join("|", @item,@removeemptylines)."\n"; } } } close $output; close $fh; }
How can i achieve this in perl? Any help would be appreciated.

Replies are listed 'Best First'.
Re: how to remove empty pipe delimiters in a line which doesn't contain any data
by toolic (Bishop) on Oct 08, 2015 at 14:08 UTC
    One way is to replace multiple pipes with one pipe using the substitution operator:
    use warnings; use strict; while (<DATA>) { s/[|]+/|/g; print; } __DATA__ IFB Northpole||| Alaska||| 907-555-5555 Walmart||| Fairbanks||| Alaska Chicken||| Anchorage||| Alaska||| 907-555-5555 Beef||| Somewhere|||||Over the Rainbow|||907-555-5555

    Outputs:

    IFB Northpole| Alaska| 907-555-5555 Walmart| Fairbanks| Alaska Chicken| Anchorage| Alaska| 907-555-5555 Beef| Somewhere|Over the Rainbow|907-555-5555
      I have tried it before the print statement in @item = @item[s/+/|/g]. it didn't work. Here is my code:
      #!/usr/bin/perl @FILES = glob("*.txt"); foreach my $file (@FILES) { open my $fh, '<', $file; (my $fileName = $file) =~ s/\.[^.]+$//; open(my $output, '>', $fileName.".csv") or die "Could not open fil +e '$fileName' $!"; my @address; my @Detail; print $output ""; while (my $line = <$fh>) { chomp $line; @tokens = split /\|/, $line; chomp(@tokens); $objectName=$tokens[0]; if($objectName ne ""){ my @objectFields; $size = scalar(@tokens); @tokens = @tokens[1..$size]; foreach my $token (@tokens){ $token =~ s/\r|\n//g; push @objectFields,$token; } if($objectName eq "IFB"){ @Detail=@objectFields; }elsif($objectName eq "Walmart"){ @address=@objectFields; }elsif($objectName eq "Chicken"){ my @item = (@Detail,@address,@objectFields); @item = @item[s/[|]+/|/g]; print $output join("|", @item)."\n"; } } } close $output; close $fh; }

        Where in that code did you use the following two lines?

        s/[|]+/|/g; print;
Re: how to remove empty pipe delimiters in a line which doesn't contain any data
by Athanasius (Archbishop) on Oct 08, 2015 at 14:35 UTC

    Hello rpinnam,

    For reading a CSV or similar file, a module such as Text::CSV is usually the best idea. Yes, it may seem like overkill, but, unless you can be certain there will never be any edge cases (string-embedded delimiters, embedded newlines, ...) in your data files, you’ll benefit from using a dedicated module in the long run. Here’s a demonstration adapted from toolic’s answer and the module documentation:

    #! perl use strict; use warnings; use Text::CSV; my $csv = Text::CSV->new({ sep_char => '|' }) or die "Cannot use CSV: " . Text::CSV->error_diag; while (my $line = <DATA>) { $csv->parse($line); my @fields = grep { !/^\s*$/ } $csv->fields; print join('|', @fields), "\n"; } $csv->eof or $csv->error_diag; __DATA__ IFB Northpole||| Alaska||| 907-555-5555 Walmart||| Fairbanks||| Alaska Chicken||| Anchorage||| Alaska||| 907-555-5555 Beef||| Somewhere|||||Over the Rainbow|||907-555-5555

    Output:

    0:31 >perl 1397_SoPW.pl IFB Northpole| Alaska| 907-555-5555 Walmart| Fairbanks| Alaska Chicken| Anchorage| Alaska| 907-555-5555 Beef| Somewhere|Over the Rainbow|907-555-5555 0:31 >

    Hope that helps,

    Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

Re: how to remove empty pipe delimiters in a line which doesn't contain any data
by Your Mother (Archbishop) on Oct 08, 2015 at 14:44 UTC

    You got pretty much all the right answers in all the good idioms already. But it sounds to me like you are breaking your data. The placement at least once corresponded to some sort of meaningful column, unless the original dev was a complete jackass. So you will be removing implicit meaning and if there are data anywhere in the mostly empty columns you'll end up sorry about the "cleaning" you're attempting.

    Update: s/DERP/you're/

Re: how to remove empty pipe delimiters in a line which doesn't contain any data
by hippo (Archbishop) on Oct 08, 2015 at 14:10 UTC
    s/\|+/|/g;

    This is assuming that the trailling pipe at the end of your first line of desired output is a typo.

    Update: Too slow :-) Also, toolic's reply nudged me to remove the unnecessary escape in the replacement string.

Re: how to remove empty pipe delimiters in a line which doesn't contain any data
by trippledubs (Deacon) on Oct 08, 2015 at 14:37 UTC
Re: how to remove empty pipe delimiters in a line which doesn't contain any data
by Tux (Canon) on Oct 08, 2015 at 14:45 UTC

    An alternative would be to use Text::CSV_XS, but I bet that won't be too fast either:

    #!/pro/bin/perl use 5.20.2; use warnings; our $VERSION = "1.00"; use Text::CSV_XS qw( csv ); csv (in => *DATA, sep => "|", allow_whitespace => 1, quote_char => undef, escape_char => undef, on_in => sub { @{$_[1]} = grep m/\S/ => @{$_[1]} }); __END__ IFB Northpole||| Alaska||| 907-555-5555 Walmart||| Fairbanks||| Alaska Chicken||| Anchorage||| Alaska||| 907-555-5555 Beef||| Somewhere|||||Over the Rainbow|||907-555-5555

    -->

    IFB Northpole|Alaska|907-555-5555 Walmart|Fairbanks|Alaska Chicken|Anchorage|Alaska|907-555-5555 Beef|Somewhere|Over the Rainbow|907-555-5555

    Enjoy, Have FUN! H.Merijn
Re: how to remove empty pipe delimiters in a line which doesn't contain any data
by johngg (Canon) on Oct 08, 2015 at 18:47 UTC

    readline the file into a map, chomp the line terminator, split on pipes, grep for length to remove empty fields and pass to a second map as an anonymous array which you join with pipes again.

    $ perl -Mstrict -Mwarnings -E ' open my $inFH, q{<}, \ <<EOF or die $!; IFB Northpole||| Alaska||| 907-555-5555 Walmart||| Fairbanks||| Alaska Chicken||| Anchorage||| Alaska||| 907-555-5555 Beef||| Somewhere|||||Over the Rainbow|||907-555-5555 EOF say for map { join q{|}, @$_ } map { chomp; [ grep { length } split m{\|} ] } <$inFH>;' IFB Northpole| Alaska| 907-555-5555 Walmart| Fairbanks| Alaska Chicken| Anchorage| Alaska| 907-555-5555 Beef| Somewhere|Over the Rainbow|907-555-5555 $

    I hope this is helpful.

    Cheers,

    JohnGG

A reply falls below the community's threshold of quality. You may see it by logging in.