Tuesday, December 28, 2010

Scope of the Perl special variables $1 to $9



 Perl contains local special variables $1 to $9.  These variables contains the sub patterns which are matched from the earlier pattern.  For example:
#!/usr/bin/perl

my $var="Perl is beautiful";
my $var1="Perl is beautiful";
$var =~ m/(\w+) (.*)/;
print "The first word is: ", $1, "\n";
print "The remaining part is: ", $2, "\n";


Output:
The first word is: Perl
The remaining part is: is beautiful
  In the above snippet, we are trying to match 2 sub-patterns in the variable var. The first sub-pattern is the first word, the second sub-pattern is the remaining sentence of the string. The output got printed as expected through the variables $1 and $2.

 However, the scope of these special variables $1 to $9 remains till the end of the block unless a new successful pattern is matched again. This might give issues in some scenarios. For example:
#!/usr/bin/perl

my $var="Perl is beautiful";
$var =~ m/Perl (.*)/;
print "Remaining: ", $1, "\n";
$var =~ m/Python (.*)/;
print "Remaining: ", $1, "\n";
Output:
Remaining: is beautiful
Remaining: is beautiful
  The output looks surprising. Isn't it? At the first look, it looks like the first print statement will print "is beautiful", and the second print statement prints none because the word python does not match. This is not the case however. The second statement will also print "is beautiful".  It is so because when the pattern matching is done the second time for the word Python, no match is found for the regular expression. In this case, Perl does not reset or clear the earlier values of $1 to $9, it retains those values. And hence "is beautiful" gets  printed in the second print statement as well. The scope of these variables remain till the end of the block in which the last successful pattern is matched.

  In order to avoid these kind of errors, the programmer should always make it a point to print those special variables only on condition check. For example:
#!/usr/bin/perl

my $var="Perl is beautiful";
if ($var =~ m/Perl (.*)/){
        print "Remaining: ", $1, "\n";
}else {
        print "No match found for Perl.\n";
}
if ($var =~ m/Python (.*)/){
        print "Remaining: ", $1, "\n";
}else {
        print "No match found for Python.\n";
}
Output:
Remaining: is beautiful
No match found for Python.
  In the above example, only if the pattern match is found, the result is printed.

No comments:

Post a Comment