Mahmoud Emam
Mahmoud Emam

Reputation: 1527

Regular expression grouping in Perl

I have variable contains: No such file or directory at ./EMSautoInstall.pl line 50.

I want to create variable contains No such file or directory and another one contains at ./EMSautoInstall.pl line 50.

my REGEX is: my ( $eStmnt, $lineNO ) = $! =~ /(.*[^a][^t])(.*)/;

when I print both variable, the first one contains No such file or directory but the second one is empty.

Why this happen?

Upvotes: 2

Views: 191

Answers (3)

TLP
TLP

Reputation: 67900

Do you really have that string in the $! variable? Because normally, the at line... part is added by die and warn. I suspect you simply have

$! = "No such file or directory";

And your regex matches because it allows the empty string

/(.*[^a][^t])(.*)/

I.e. the second capture also matches nothing, and the first capture can be anything that does not end with at.

To confirm,

print $!;

Should print No such file or directory.

Upvotes: 7

Casimir et Hippolyte
Casimir et Hippolyte

Reputation: 89547

You can use this:

((?:[^a]+|\Ba|a(?!t\b))+)(.*)

the idea is to match all that is not a "a" or a "a" that is not a part of the word "at"

details:

(                 # first capturing group
    (?:           # open a non capturing group
        [^a]+     # all that is not a "a" one or more times
      |           # OR
        \Ba       # a "a" not preceded by a word boundary
      |           # OR
        a(?!t\b)  # "a" not followed by "t" and a word boundary
    )+            # repeat the non capturing group 1 or more times
)                 # close the capturing group
(.*)              # the second capturing group  

You can improve this pattern replacing the non-capturing group by an atomic group and the quantifiers by possessive quantifiers. The goal is to forbid the record by the regex engine of backtrack positions, but the result stay the same:

((?>[^a]++|\Ba|a(?!t\b))++)(.*+)

Upvotes: 1

Zaid
Zaid

Reputation: 37136

Using split here with a lookahead assertion makes more sense than regex captures:

my ( $eStmnt, $lineNO ) = split /(?=at)/, $!;

Upvotes: 2

Related Questions