Search code examples
regexperlsmartmatch

Why is this regex from a text file not working with smartmatch?


I use smartmatch to check whether a string matches a regex pattern. It stopped working after I decided to store the regex in a text file.

my $str   = '123456, some text.';
my $regex = qr/^\d+, some text\.$/;
print "Regex: $regex\n";

At this point, the printed regex is (?^:^\d+, some text\.$). I copy-paste it into a file, then I make the code read the file and retrieve the regex, which is stored in $regexFromFile.

The following line confirms that $regex and $regexFromFile are the same, then I proceed to test $str against the regex in various ways.

print 'Is regex equal to regexFromFile? ' . ($regex eq $regexFromFile) . "\n";

print 'Does str match regex         using =~ ? ' . ($str =~ $regex)         . "\n";
print 'Does str match regexFromFile using =~ ? ' . ($str =~ $regexFromFile) . "\n";
print 'Does str match regex         using ~~ ? ' . ($str ~~ $regex)         . "\n";
print 'Does str match regexFromFile using ~~ ? ' . ($str ~~ $regexFromFile) . "\n";

The last line of that code does not behave the same as the previous three lines.

Here is the complete output of the code:

Regex: (?^:^\d+, some text\.$)
Is regex equal to regexFromFile? 1
Does str match regex         using =~ ? 1
Does str match regexFromFile using =~ ? 1
Does str match regex         using ~~ ? 1
Does str match regexFromFile using ~~ ? 

(Note the absence of 1 at the end.)

Edit: To answer a comment, here is how the file is read.

open(my $FILEHANDLE, 'file.txt') or die "Error: Could not open file.\n";
my @content = <$FILEHANDLE>;
close($FILEHANDLE) or print "Could not close file.\n";
my @content_woEol = ();
foreach my $line (@content){
    $line =~ s/\s*$//;
    push(@content_woEol, $line);
}
my $regexFromFile = $content_woEol[0];

Solution

  • The result of qr// is actually a precompiled regular expression. Copy-pasting the printed regular expression to a file, as you did, then reading it from the file, is not the problem. You would experience the same behavior had you written this line directly in your code:

    my $regexFromFile = '(?^:^\d+, some text\.$)';
    

    If you want to use smatmatch here, I would advise you to do something like the following:

    my $str   = '123456, some text.';
    my $regex = '^\d+, some text\.$';
    
    # Manually store this in the file: ^\d+, some text\.$
    # Read $regexFromFile from the file
    
    print 'Does str match regex         using =~ ? ' . ($str =~ /$regex/)         . "\n";
    print 'Does str match regexFromFile using =~ ? ' . ($str =~ /$regexFromFile/) . "\n";
    print 'Does str match regex         using ~~ ? ' . ($str ~~ /$regex/)         . "\n";
    print 'Does str match regexFromFile using ~~ ? ' . ($str ~~ /$regexFromFile/) . "\n";
    

    Note the additional /.../. Output:

    Does str match regex         using =~ ? 1
    Does str match regexFromFile using =~ ? 1
    Does str match regex         using ~~ ? 1
    Does str match regexFromFile using ~~ ? 1