Beefy Boxes and Bandwidth Generously Provided by pair Networks
Your skill will accomplish
what the force of many cannot
 
PerlMonks  

clean code

by rsiedl (Friar)
on Apr 20, 2006 at 12:42 UTC ( [id://544582]=perlquestion: print w/replies, xml ) Need Help??

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

hey monks,

a quick one, can anyone suggest a cleaner way to do the following?
my (@vals) = split(/\;/, $memory_data); foreach my $mem (@vals) { my ($mem_name,$mem_value) = split(/\=/, $mem); $data{$mem_name} = $mem_value; } # end-foreach
Cheers
Reagen

Replies are listed 'Best First'.
Re: clean code
by Zaxo (Archbishop) on Apr 20, 2006 at 12:52 UTC

    I think I'd make it a straight initialization from a list, using a split on either separator:

    my %data = split /[=;]/, $memory_data;
    That's a little reliant on the data being what you expect (anything but one "=" in a record is unsupported). It reduces the temporary variables and looping quite a bit.

    After Compline,
    Zaxo

Re: clean code
by gellyfish (Monsignor) on Apr 20, 2006 at 12:50 UTC

    Dunno about 'cleaner' (everyone has their own understanding of that term) but certainly more succinct:

    my $memory_data = 'foo=bar;zub=baz;yar=grr'; + my %data; + $data{$1} = $2 while $memory_data =~ /([^=;]+)=([^;]+)/g;

    /J\

Re: clean code
by Samy_rio (Vicar) on Apr 20, 2006 at 12:50 UTC

    Hi rsiedl, Try this,

    use strict; use warnings; my $memory_data = "foo=bar;perl=japh;"; my %data; %data = map{split/\=/,$_} split(/\;/, $memory_data); print "$_\t$data{$_}\n"for keys(%data); __END__ perl japh foo bar

    Regards,
    Velusamy R.


    eval"print uc\"\\c$_\""for split'','j)@,/6%@0%2,`e@3!-9v2)/@|6%,53!-9@2~j';

Re: clean code
by jhourcle (Prior) on Apr 20, 2006 at 13:14 UTC
    use CGI; my %data = CGI->new( $memory_data )->Vars();

    Of course, that assumes there's no key defined twice, or it won't give the same results. (multiple keys will results in a null (\0) seperated list of all possible values, rather than just the last value for the given key). It'll also do URI decoding, so % and + will get converted.

Re: clean code
by dragonchild (Archbishop) on Apr 20, 2006 at 13:16 UTC
    use CGI::Simple; my $data = CGI::Simple->new( $memory_data ); # At this point, you just do $data->param( 'foo' ) to retrieve the val +ue # associated with 'foo'. Instead of what you're doing which is $data{ +'foo' };

    My criteria for good software:
    1. Does it work?
    2. Can someone else come in, make a change, and be reasonably certain no bugs were introduced?
Re: clean code
by blazar (Canon) on Apr 20, 2006 at 13:53 UTC

    Pleonastic quoting and parentheses decrease the ease with which I can read code. But a map is well suited for this task:

    my %data=map +(split /=/)[0,1], split /;/, $memory_data;

    The [0,1] thing is there just in case split /=/ would return more than two entries, which may be possible. Depending on the reliability of your input you may either leave it out altogether or on the contrary add more strict checks.

    Also, this assumes you want to fill %data all at once. If you're just adding (and possibly replacing) key-value pairs to it instead, then just:

    %data=(%data, map +(split /=/)[0,1], split /;/, $memory_data);
Re: clean code
by creamygoodness (Curate) on Apr 20, 2006 at 19:45 UTC

    I pretty much like what you have already! It's easy to understand and robust. The only thing I think you really ought to change are the backslashes in the split regexes, which shouldn't be there.

    All the other changes I'd make are superficial. Structurally, the temporary variable @vals can be eliminated by putting it within the loop initializer. Stylistically, I think you ought to leave off the comment marking the end of the loop, as you're already practicing proper indentation, and that's sufficient. Here's some code I might have written:

    # extract name-value pairs from serialized database row for my $pair ( split( /;/, $serialized_row ) ) { my ( $name, $value ) = split( /=/, $pair ); $record{$name} = $value; }
    --
    Marvin Humphrey
    Rectangular Research ― http://www.rectangular.com
      Make that split(/=/, $pair, 2) and your values will be allowed to have equals signs.

      For most casual applications, I usually use split(/\s*=\s*/, $pair, 2). I like spaces. I'd do the same for the semicolon split. But considering the comment (this is from a serialized db row), I doubt there's much point.

      To be more robust (specifically: to allow arbitrary characters in the names and values), I agree with the suggestions to use URI escaping. Since you're programmatically generating the data you're parsing, there's no reason not to do the job right -- your first concern should be correctness, second should be basic human readability (so you can tell what's going on), and a very distant third should be human writability (for debugging, casual testing, off-the-cuff model manipulation, etc.)

        sfink++ on the additional argument to split().

        As for the comment, the original post did not make clear the purpose of the code block. I always code in commented paragraphs (as per Perl Best Practices), and such comments should be as specific as possible. However, I didn't want to make a big deal about that personal stylistic choice it because it wasn't germane.

        Several other posters made what I think was a reasonable assumption that the purpose of the block was CGI processing, presumably based on the structure of the data and the name of the $memory_data variable. Processing of CGI query strings raises a host of issues I didn't want to get into, so I made a different assumption about the nature of the data. :)

        --
        Marvin Humphrey
        Rectangular Research ― http://www.rectangular.com
Re: clean code
by Gilimanjaro (Hermit) on Apr 21, 2006 at 10:58 UTC

    regex for teh win!

    %data = $memory_data =~ /([^=]+)=([^;]*);?/g;

    at least, depending on your definition on 'clean'...

    update: I now noticed that my regex is almost identical to gellyfish's, but I assign directly to the hash...

Re: clean code
by bart (Canon) on Apr 23, 2006 at 11:16 UTC
    You've got a bit of superfluous characters. And your variables, which are lexically scoped to the block (= invisible outside that block), can have much simpler names.
    foreach my $mem (split /;/, $memory_data) { my($name,$value) = split /=/, $mem, 2; $data{$name} = $value; }
    I don't think this is that bad.

    I've applied sfink's advice, which is my recommendation too.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://544582]
Approved by Happy-the-monk
Front-paged by ff
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others musing on the Monastery: (2)
As of 2024-04-25 04:39 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found