ILoveNachos
ILoveNachos

Reputation: 23

Can someone explain me this regex in perl?

There's a program that use a regex and somehow I can't manage to understand it.

The code goes +- like this:

@listOfIds = &methodToGetIDs();
foreach my $id (@listOfIds){
    if($class =~ /gen/ig){
        #does stuff
    }
}

What I understand is that if $class has "gen" then it will get into the if{} but sometimes it won't get into it, so I put an else to see what was happening and the code end up like this:

my $class = "genes";
foreach my $id (@listOfIds){
    if($class =~ /gen/ig){
        print $class."\n"; #to see the value of class
    }else{
        print "!!!".$class."\n";   #to see the difference if there's any
    }#miss this wooops!
}

Guess what? the output was like this:

genes
genes
!!!genes
genes
genes
!!!genes
genes
genes
!!!genes

If the value of $class doesn't change then why does it gets into the else clause? Guess I don't understand regular expressions at all. Any clues?

Upvotes: 2

Views: 93

Answers (2)

cbmckay
cbmckay

Reputation: 496

Because you are using the /g option. From perlop :

In scalar context, each execution of m//g finds the next match, returning true if it matches, and false if there is no further match. The position after the last match can be read or set using the pos() function; see pos. A failed match normally resets the search position to the beginning of the string, ...

So, you are getting a match the first time you look at the string. Then, the next time you are starting after the position of the first match. I.e. the position is not reset to the start of the string, it continues on where the first match occurs.

The /g flag is used to indicate you want to match all the times you can in the string. That is useful for counting how many times a substring occurs in the string. In your case, you are testing to see if the pattern matches at all, true, and if it does, do something. You don't need the /g flag in this case.

my $class = "genes";

foreach my $id (1..6){ 
    if($class =~ /gen/ig){
        print $class."\n"; #to see the value of class
    }else{
        print "!!!".$class."\n";   #to see the difference if there's any
    }
}

outputs:

genes                                                                                                                                                                           
!!!genes                                                                                                                                                                        
genes                                                                                                                                                                           
!!!genes                                                                                                                                                                        
genes                                                                                                                                                                           
!!!genes

while if you remove the /g flag you get:

genes                                                                                                                                                                           
genes                                                                                                                                                                           
genes                                                                                                                                                                           
genes                                                                                                                                                                           
genes                                                                                                                                                                           
genes

Upvotes: 2

nothingmuch
nothingmuch

Reputation: 1516

The perlop manpage reads:

In scalar context, each execution of m//g finds the next match, returning true if it matches, and false if there is no further match.

Since if evaluates the condition in scalar context in your expression, every time it'll first return true, and then false as there are no further matches (I don't understand why it prints twice, and your code doesn't compile).

But note that:

if ( $class =~ /gen/i ) {

will always be true in your example, since $class = "genes" and doesn't appear to change. Did you mean to check $id instead?

At any rate, the /g modifier doesn't seem appropriate for your code.

Upvotes: 0

Related Questions