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

hi all

I have a array consisting of words occupying each cell and in that array I also have ! at certain places occupying a cell individually . so i want that from one ! to other ! entire thing should go to a new array cell

say for instance " ! my name ! is !Achint ! I need ! help

I have an array where '!' is in zero cell 'my' is in one cell , 'name' is in second '!' in third "is " in forth '!' in fifth , so now i want from one '!' to other '!' i.e "my name" should go in one array cell , "is" into other .

so how can i do it , because split will not work

Replies are listed 'Best First'.
Re: Separating array contents
by space_monk (Chaplain) on Jun 07, 2013 at 07:50 UTC
    split will work, join all the array cells together into one string, then split on the ! characters

    Update: some Monks have rained on my parade by noting that this may produce empty elements. :-) You can filter out empty elements with map or grep -(see below)

    my $string = join( '', @mycells); my @result = split( '!', $string); # remove empty elements, using something like.... my @finalResult = grep { $_ ne '' }, @result;
    If you spot any bugs in my solutions, it's because I've deliberately left them in as an exercise for the reader! :-)
      Great. I thought of the same solution too, but I feared it would be too slow. I was not able to come with a faster one, though:
      #!/usr/bin/perl use warnings; use strict; use Test::More; use Benchmark qw(cmpthese); my @arr_s = qw/! my name ! is ! Achint ! I need ! help/; my @arr_ns = qw/ my name ! is ! Achint ! I need ! help/; sub simple { my @arr1 = split / *(!) */, join(' ', @_); shift @arr1 unless length $arr1[0]; return \@arr1; } sub complex { my @arr2; my $x = 0; my $step = 1; for (@_) { if ('!' eq $_) { $x += $step; push @arr2, '!'; } else { $arr2[$x] .= (defined $arr2[$x] ? ' ' : q()) . $_; } $step = 2; } return \@arr2; } print join ' # ', @{simple(@arr_s)}, "\n"; print join ' | ', @{simple(@arr_ns)}, "\n"; is_deeply([simple(@arr_s )], [complex(@arr_s )]); is_deeply([simple(@arr_ns)], [complex(@arr_ns)]); done_testing(); cmpthese(-5, { simple => sub { simple(@arr_s); simple(@arr_ns) }, complex => sub { complex(@arr_s); complex(@arr_ns) }, });

      Results on my netbook:

      Rate complex simple complex 10723/s -- -5% simple 11262/s 5% --
      لսႽ† ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ

        Thank you for helping out

      Thank you for helping out

Re: Separating array contents
by hdb (Monsignor) on Jun 07, 2013 at 09:18 UTC

    This creates an array of arrays split at "!", potentially with empty entries at beginning or end. Similar to choroba's complex solution in Re^2: Separating array contents

    use strict; use warnings; use Data::Dumper; my @arr = qw/ ! my name ! is ! Achint ! I need ! help ! /; my @out = ( [] ); for( @arr ) { if( /^!$/ ) { push @out, []; } else { push @{ $out[-1] }, $_; } } print Dumper \@out;

      If you don't like empty entries you can simply push the result array through a map or grep filter.

      If you spot any bugs in my solutions, it's because I've deliberately left them in as an exercise for the reader! :-)
Re: Separating array contents
by tobias_hofer (Friar) on Jun 07, 2013 at 07:53 UTC
    Hi,

    I do these things like this using split function:
    #First you should join the array first, like shown by space_monk above +. #Then you got something like that.. my $string = "! my name ! is !Achint ! I need ! help"; #Here the '!' is the delimiter. my @Array = split(/!/,$string); print @Array;
    Hope this helps! ;-) I know this is now quite redundant - sorry for that!
Re: Separating array contents
by jnyman (Acolyte) on Jun 07, 2013 at 08:53 UTC
    Suggestion:
    use 5.014; use Data::Dumper; my @arr = ('!', 'my', 'name', '!', 'is ', '!'); my $joined = join '' => map { s/^\s+|\s+$//g; $_ } @arr; $joined =~ s/^!|!$//g; my @result = split /!/ => $joined; say Dumper(@result);
    This will handle the !-character in the beginning so that it won't generate an empty cell. It also trims the strings in the cells as in your description you had "is " -> "is". Update: improved trim regex
Re: Separating array contents
by johngg (Canon) on Jun 07, 2013 at 17:27 UTC

    If there is no trailing delimiter, as in your posted text, you can do this:-

    $ perl -Mstrict -Mwarnings -E ' my $str = q{!one ! two!three and four! five}; my @arr = reverse map { scalar reverse } split m{\s*!\s*}, scalar reverse $str; say qq{>$_<} for @arr;' >one< >two< >three and four< >five< $

    If there is a trailing delimiter then you will still have the problem of an empty leading element so there would be no advantage to using this.

    I hope this is of interest.

    Cheers,

    JohnGG

Re: Separating array contents
by hbm (Hermit) on Jun 07, 2013 at 18:26 UTC
    perl -E "$_ = q{!! !one ! two!three and four! five!! !}; say for /\w +[\w ]+\w/g" one two three and four five