http://www.perlmonks.org?node_id=585682

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

I need to extract 2 arrays from a string. The input string is: A: Gold, Black, Purple, Blue, Red B: Black, Neon Pink, Neon Yellow, Neon Green, Neon Purple, Red, White, Neon Orange, Navy The output which i should get is: Array A: Gold, Black, Purple, Blue, Red Array B; Black, Neon Pink, Neon Yellow, Neon Green, Purple, Red, White, Neon Orange, Navy The code which i tried is this:
use strict; use warnings; $| = 0; my $str="A: Gold, Black, Purple, Blue, Red B: Black, Neon Pink, Ne +on Yellow, Neon Green, Neon Purple, Red, White, Neon Orange, Navy"; my @arrayA; my @arrayB; map {push @{(\@arrayA, \@arrayB)[--$|]}, split /,/} split /\s+/, $str; print "Array A:@arrayA\n"; print "Array B: @arrayB";
I am getting the result like this:
Array A:Gold Purple Red Black Pink Yellow Green Purple White Orange Array B: A: Black Blue B: Neon Neon Neon Neon Red Neon Navy
Which is not correct. Thanks monks for all your suggestions and help.

Replies are listed 'Best First'.
Re: string manipulations.
by davido (Cardinal) on Nov 23, 2006 at 08:26 UTC

    In the CB I was ineffectively trying to suggest that instead of @arrayA and @arrayB, you could more conveniently use a hash of arrays like this:

    use strict; use warnings; my $str="A: Gold, Black, Purple, Blue, Red B: Black, Neon Pink, Ne +on Yellow, Neon Green, Neon Purple, Red, White, Neon Orange, Navy"; my %arrays; my( @substrings ) = $str =~ m/(\w:\s*.+?)(?=\w:|$)/g; foreach my $substring ( @substrings ) { my( $key, $colors ) = split /:\s*/, $substring; my( @colors ) = split /,\s*/, $colors; $arrays{ $key } = [ @colors ]; } foreach my $key ( sort keys %arrays ) { print "Array $key: @{$arrays{$key}}\n"; }

    With this approach you're not stuck trying to treat diversely named variables as if they're a set (which is what you're trying to do when you deal with @arrayA and @arrayB). The hash approach holds both arrays as anonymous arrays referred to by the reference held in key A and key B. Hash key manipulation is much easier to do than contortions with variable names. The road down which you were traveling would eventually lead you to a desire to use symbolic references. The road my approach takes you down leads to proper references; much easier and safer to work with.

    I'd have a look at perlref, perlreftut, and perllol, and finally, perldsc for more insight. I know it's a lot of reading, but spend a couple hours with it, and you'll be miles ahead on the learning curve.


    Dave

      First thanks all for your solutions. But the problem is in the array B, i have colors such as Neon Pink, Neon Yellow, Neon Green, Neon Purple etc. when using split it splits into Neon one element and Pink one element and so on. But Neon Pink is a single color. Because each element i am storing in an array and inserting into database. so the single element splits into two. Also i have colors like Translucent Navy, Purple Ice, Blue Ice etc. any ideas. thanks all for your suggestions.

        You didn't test my solution. If you reject my solution, at least test it first. What I provided splits on ',' (comma), and thus it's impossible for it to foul up in the way you're saying it does. I just tested it myself and found its behavior to be as you need, not as you're describing; it splits on comma, not on space.

        If you need reassurance, add the following line to the top of the script: $" = "/ ";

        If you do that, you'll see in the output clearly that the colors are being split correctly in the solution I provided.


        Dave

Re: string manipulations.
by jwkrahn (Abbot) on Nov 23, 2006 at 08:34 UTC
    Maybe you should be using a Hash of Arrays:
    $ perl -le' my $str = "A: Gold, Black, Purple, Blue, Red B: Black, Neon Pink, +Neon Yellow, Neon Green, Neon Purple, Red, White, Neon Orange, Navy"; my %hash = map s/:// ? $_ : [ split /\s*,\s*/ ], grep length, split /\ +s*(\w+:)\s*/, $str; use Data::Dumper; print Dumper \%hash; ' $VAR1 = { 'A' => [ 'Gold', 'Black', 'Purple', 'Blue', 'Red' ], 'B' => [ 'Black', 'Neon Pink', 'Neon Yellow', 'Neon Green', 'Neon Purple', 'Red', 'White', 'Neon Orange', 'Navy' ] };
Re: string manipulations.
by holli (Abbot) on Nov 23, 2006 at 08:32 UTC
    somewhat similar to davido's solution, but using split:
    use strict; use warnings; my $str="A: Gold, Black, Purple, Blue, Red B: Black, Neon Pink, Ne +on Yellow, Neon Green, Neon Purple, Red, White, Neon Orange, Navy"; # create a hash using the A:, B: parts as keys and the following strin +gs as values my %str = grep { $_ } map { s/^\s+//; s/\s+$//; $_; } split /([A-Z]:)/, $str; # iterate the hash and make the value strings to # arrayrefs for ( sort keys %str ) { $str{$_} = [ split /, /, $str{$_} ]; } # output for ( sort keys %str ) { print "Array $_ ", join (", ", @{$str{$_}}), "\n"; }


    holli, /regexed monk/
Re: string manipulations.
by GrandFather (Saint) on Nov 23, 2006 at 10:05 UTC

    Or as an array of arrays:

    use strict; use warnings; $| = 0; my $str="A: Gold, Black, Purple, Blue, Red B: Black, Neon Pink, Ne +on Yellow, Neon Green, Neon Purple, Red, White, Neon Orange, Navy"; my @records; my @strings = $str =~ m/(\w+:(?:(?!\b\w+:).)*)/g; push @records, map {[m/(\w+:)/, m/(?<=:|,)\s([^,]*,?)/g]} @strings; print "@$_\n" for @records;

    Prints:

    A: Gold, Black, Purple, Blue, Red B: Black, Neon Pink, Neon Yellow, Neon Green, Neon Purple, Red, White, + Neon Orange, Navy

    DWIM is Perl's answer to Gödel