Georg
Georg

Reputation: 1098

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];

Upvotes: 0

Views: 142

Answers (3)

ikegami
ikegami

Reputation: 385887

Smartmatching is broken. Please avoid using it.[1]

$str is a string, and $regexFromFile is a string, so $str ~~ $regexFromFile is equivalent to $str eq $regexFromFile.

If you wanted $str ~~ $regexFromFile to be equivalent to $str =~ $regexFromFile, you'd have to convert the misnamed $regexFromFile from a string into a regex (e.g. using qr//). Of course, the far better solution is to simply use =~.


  1. Many years ago, it was made experimental as a form of deprecation so it could be fixed. Continued use of this broken feature actually prevented a recent effort to fix it.

Upvotes: 4

user8487873
user8487873

Reputation: 190

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

Upvotes: 2

Borodin
Borodin

Reputation: 126722

Smartmatch has been experimental since v5.18 and should never have been used in live production software

It has always required

use feature 'switch';

And unless you are someone who consciously or explicitly ignores warnings, with

no warnings qw/ experimental::smartmatch /;

then you will have had ample warning of its demise

You have made an informed choice that was clearly wrong from the start

Upvotes: -1

Related Questions