简体   繁体   中英

How to filter each array elements according to a regex

I have an array with elements like this:

@ORF= (MEZQFVECQWSXC*FVCXRCT*, MAEZCRTDRX*AZEFZC*AZERC*)

I want to split every array so that each elment starts with 'M' and ends with '*' , no extra '*' in between.

so my example above should give me

@ORF = (MEZQFVECQWSXC*,MAEZCRTDRX*)

I thought about first splitting each elements like this:

    foreach (@ORF) {
        my $true= split /\*/, $_;
        push @ORF, $true
}

and then splicing the others out with and if statement, but this does not work.

I also considered using grep

@ORF= grep m/M.*\*/, @ORF;

But this does not affect the array.

I am getting increasingly confused and google is not helping... Please help me out?

You can indeed do that with split and a loop. You can also use map instead of a for loop.

use strict;
use warnings;
use Data::Printer;

my @ORF= ('MEZQFVECQWSXC*FVCXRCT*', 'MAEZCRTDRX*AZEFZC*AZERC*');
@ORF = map { (split /\*/, $_, 0 )[0] . '*' } @ORF;

p @ORF;

It will iterate over every element in @ORF and split on the * . The 0 as the thrid parameter tells split to only split once. Treat the return value as a list and only take the first element ( [0] ), put back the asterisk and you've got yourself a new list of strings that start with the M and ends with the asterisk.

[
    [0] "MEZQFVECQWSXC*",
    [1] "MAEZCRTDRX*"
]

Of course that assumes there are only strings that match this pattern without checking.


A simpler way would be to use substr and index to find the first occurance of the * and take the beginning of the string until that character. That's probably more like what you wanted to do with the splice , but misunderstood what that does.

@ORF = map { substr $_, 0 , index($_, '*') + 1 } @ORF;
 foreach (@ORF) { my $true= split /\\*/, $_; push @ORF, $true } 

This was actually very close to the solution. There were just a couple of problems.

Firstly, you're assigning the return value from split to a scalar variable. And in scalar context, split returns the number of items it can split the string into, not the items themselves. So you'll just get the value 2. We can fix that by making it a list assignment.

my ($true) = split /\*/, $_;

Secondly, you're push ing your new value on to the end of @ORF . This means that @ORF just keeps getting longer and your loop never ends. You need to replace the current element of the array with your new value. And you can do that by assigning to $_ .

So the whole loop becomes:

foreach (@ORF) {
    my ($true) = split /\*/, $_;
    $_ = "$true*";
}

Having said all that, I do prefer simbabque 's map solution .

if you like, you could also use map+grep, like so:

use Data::Dumper;

my @ORF= ("MEZQFVECQWSXC*FVCXRCT*", "MAEZCRTDRX*AZEFZC*AZERC*");
@ORF = grep { $_ =~ /^M/ } map { (split/\*/, $_)[0] . '*' } @ORF;
print Data::Dumper->Dump(\@ORF);

Result:

$VAR1 = 'MEZQFVECQWSXC*';
$VAR2 = 'MAEZCRTDRX*';

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM