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

Well I'm at a loss why my code below does not work as expected... SO much so I don't even know what to search for.

My appologizes if a similar question has been asked before in the past.

I am trying to work around an issue I have with split (is their a more elegant solution?) in which my input data has null fields. Split unfortently doesn't set my vars to null.

My data also is not consistant in the number of fields (I am processing passwd files AND shadow files).

So to "fix" that I figure I'll just change the input and move on. The only prob is that it doesn't work as I expected.

Can anyone explain what is happening?

Thanks for your time!

#!/usr/local/bin/perl use strict; use warnings; # # I want to shove the string NULL into place to make # my split work as expected. # # Ie if I split $line I only get 3 fields when I want 9. # I want an empty/null field to be set to null. # my $line="root:XXXXXXXXXXXXX:12103::::::"; # I want the above to become This: print "My Goal: root:XXXXXXXXXXXXX:12103:NULL:NULL:NULL:NULL:NULL:N +ULL\n\n"; print "\nWhy does this not work?\n"; print "\tBEFORE\t$line\n" if ( $line =~ /^root:/ ); # UGLY UGLY UGLY UGLY. you have a better idea? $line=~s/::/:NULL:/g; $line=~s/:$/:NULL/g; print "\tAFTER\t$line\n" if ( $line =~ /^root:/ ); $line="root:XXXXXXXXXXXXX:12103::::::"; print "\nThis is an ugly ugly ugly solution:\n"; print "\tBEFORE\t$line\n" if ( $line =~ /^root:/ ); # UGLY UGLY UGLY UGLY. you have a better idea? $line=~s/::/:NULL:/g; $line=~s/::/:NULL:/g; # argh! $line=~s/:$/:NULL/g; print "\tAFTER\t$line\n" if ( $line =~ /^root:/ );

The output:

Why does this not work?

BEFORE root:XXXXXXXXXXXXX:12103::::::

AFTER root:XXXXXXXXXXXXX:12103:NULL::NULL::NULL:NULL

This is an ugly ugly ugly solution:

BEFORE root:XXXXXXXXXXXXX:12103::::::

AFTER root:XXXXXXXXXXXXX:12103:NULL:NULL:NULL:NULL:NULL:NULL

Replies are listed 'Best First'.
Re: Perl subsititution oddities...
by BrowserUk (Patriarch) on Oct 01, 2003 at 19:16 UTC

    Or using split with a 3rd argument of -1 to prevent it from dropping null elements and map to substitute the 'NULL's.

    print join':', map{ $_ eq '' ? 'NULL' : $_} split ':', 'root:XXXXXXXXX +XXXX:12103::::::',-1; root:XXXXXXXXXXXXX:12103:NULL:NULL:NULL:NULL:NULL:NULL

    Examine what is said, not who speaks.
    "Efficiency is intelligent laziness." -David Dunham
    "When I'm working on a problem, I never think about beauty. I think only how to solve the problem. But when I have finished, if the solution is not beautiful, I know it is wrong." -Richard Buckminster Fuller
    If I understand your problem, I can solve it! Of course, the same can be said for you.

Re: Perl subsititution oddities...
by Paladin (Vicar) on Oct 01, 2003 at 19:11 UTC
    Fixing the split would be much more elegant, unless you actually need the NULL in each empty field. From perldoc -f split:

    By default, empty leading fields are preserved, and empty trailing ones are deleted.

    ...

    If LIMIT is unspecified or zero, trailing null fields are stripped (which potential users of "pop" would do well to remember). If LIMIT is negative, it is treated as if an arbitrarily large LIMIT had been specified.

    So you can do my @array = split /:/, $line, -1; and have it keep all empty training fields.

Re: Perl subsititution oddities...
by flounder99 (Friar) on Oct 01, 2003 at 18:58 UTC
    When you match :: you are consuming both colons. Try this using a zero width lookahead:
    my $line="root:XXXXXXXXXXXXX:12103::::::"; $line=~s/:(?=:|$)/:NULL/g; print "\tAFTER\t$line\n" if ( $line =~ /^root:/ ); __OUTPUT__ AFTER root:XXXXXXXXXXXXX:12103:NULL:NULL:NULL:NULL:NULL:NULL

    --

    flounder

Re: Perl subsititution oddities...
by smellysocks (Beadle) on Oct 01, 2003 at 20:54 UTC

    Thanks for your comments.

    I had read the perldoc -f split prior to the posting, but my slow brain didn't understand the implications of the split(/pattern/,$line,-1)

    Mystery solved.

    -smelly