Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Perl writing to a 'memory file' plays tricks with pattern matching

Tags:

regex

perl

When I run this code, I get "no" printed out:

my $memory_file;
my $fh;
open ($fh, '>', \$memory_file);
print $fh "abc";
if( $memory_file =~ m/^.*$/ )
{ print "yes\n" }
else
{ print "no\n" }

If I print out $memory_file, the contents are indeed "abc".

If I change the pattern to .* (no ^ or $) it works as expected.

If I put the line $memory_file = "abc" before the match, I get 'yes' printed out (as originally expected).

What on earth is going on here?

(This is perl 5.14.1)

Update: Some more discussion on PerlMonks. It is seeming like a bug, I will log it.

Update 2: The fine Perl developers have fixed this bug: https://rt.perl.org/rt3//Public/Bug/Display.html?id=108398

like image 263
jwd Avatar asked Dec 27 '11 22:12

jwd


1 Answers

It is the end of line character that is messing things up. While a regular assignment works:

my $str = "abc";
print "Works" if $str =~ /^.*$/;

...the code in the question does not. This regex should match any string, since it also matches the empty string. Even undefined values would match (though it would cause a warning). Also, ^.* does match.

The only reasonable explanation is that for some reason, whatever check is performed to match an end of string, it is not finding it. The end of the string is missing.

Curiously, replacing $ with \z works. But not \Z.

Adding a newline also works. Which would sort of make sense, as adding a newline would imply that an end of the string is also added, in the non-multiline regex sense.

I don't know the inner workings of why this happens, but I suspect that when using this particular form of "assignment", an end-of-the-string marker is never placed on the string. A sort of "raw" assignment, which confuses the check for end of string in the regex.

It feels like a bug. Perhaps this particular feature has not been properly maintained.

like image 70
TLP Avatar answered Sep 21 '22 14:09

TLP