📜 ⬆️ ⬇️

Peculiarities of national expressions

I wanted to share with the habravchana-perlovodami one interesting case that occurred in our work. In the process of revising the old code, some mysterious construction was discovered (hereinafter the real code is somewhat abbreviated and smoothed):
sort { my ($x, $y) = ($a, $b); ($x =~ s{/}g) <=> ($y =~ s{/}g); } @array;
It would Seem, usual sorting with redefined function of comparing. According to the original idea of ​​the author, the array of strings should be sorted by the number of direct slashes in these lines (it is known that the replacement expression returns the number of substitutions as a value), but something is not right in this function. It seems that the “substitute” part of the expression s / pattern / replace / g was never optional, but this is what we see in the expressions $a =~ s{/}g . How does it work? Here we will deal with it now.

So, the first thing that comes to mind is just to try an expression on a simple example. Ok, run and get the result:
$ perl -we 'my $a = "a/b/c"; $a =~ s{/}g; print "$a\n";'
Substitution replacement not terminated at -e line 1.
That is, our suspicions were true, the expression is not valid. How then does the original example work? After unsuccessful attempts to sort things out on our own, we called the Deparse module for help.
$ cat test.pl
my ($a, $b);
sub f {
return (($a =~ s{/}g) <=> ($b =~ s{/}g));
}
$ perl -MO=Deparse -w test.pl
BEGIN { $^W = 1; }
my($a, $b);
sub f {
return $a =~ s [ / ][ ) <=> ($b =~ s{/} ] ;
}
/home/tester/test.pl syntax OK
After a brief creak of brains, finally managed to figure out what Pearl does. In the above log, I highlighted the blue brackets on which you need to pay attention. The behavior turned out to be quite logical and documented, although somewhat unexpected. As many of the Pearl programmers should know, in the s /// operator, other symbols can be used as brackets instead of slashes (as Deparse has very clearly demonstrated using square brackets). But until that moment, it simply did not occur to me that, in the same way, the most common letter “ g ” could be used as brackets! Thus, as an expression for the search in the $ a variable, it takes what is supposed to be - one forward slash, but the text between the letters " g ", which were supposed to be modifiers of the operation, is taken as a replacement expression.

For clarity, I’ll now write the source code line again, this time highlighting the search expression in red, replacing green with brackets and marking it with the same color, but with a darker tone:
(($a =~ s { / } g ) <=> ($b =~ s{/} g ))
As a result, we have one replacement expression, not two, and our comparison function actually didn’t compare anything, but simply always gave only the number of slashes in the first argument, and instead of sorting, we got just an array mixing (and we didn’t notice this before the reason that sorting was a purely cosmetic improvement, and when using the program, no one paid particular attention to the output order of the sorted lines).

So, what is the moral? Yes, probably no. Once again, the already well-known truth was confirmed: not everything is right that compiles.

')

Source: https://habr.com/ru/post/83644/


All Articles