Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing a regex substitution as a variable in Perl

Tags:

I need to pass a regex substitution as a variable:

sub proc {     my $pattern = shift;     my $txt = "foo baz";      $txt =~ $pattern; }  my $pattern = 's/foo/bar/'; proc($pattern); 

This, of course, doesn't work. I tried eval'ing the substitution:

eval("$txt =~ $pattern;"); 

but that didn't work either. What horribly obvious thing am I missing here?

like image 337
ceo Avatar asked Sep 24 '08 03:09

ceo


People also ask

How does regex substitution work?

Substitutions are language elements that are recognized only within replacement patterns. They use a regular expression pattern to define all or part of the text that is to replace matched text in the input string. The replacement pattern can consist of one or more substitutions along with literal characters.

What is \d in Perl regex?

The Special Character Classes in Perl are as follows: Digit \d[0-9]: The \d is used to match any digit character and its equivalent to [0-9]. In the regex /\d/ will match a single digit. The \d is standardized to “digit”.

What does =~ do in Perl?

Look it up on a text on Perl. Use parentheses. The ( =~ ) operator takes two arguments: a string on the left and a regular expression pattern on the right. Instead of searching in the string contained in the default variable, $_ , the search is performed in the string specified.

How do I search and replace in Perl?

Performing a regex search-and-replace is just as easy: $string =~ s/regex/replacement/g; I added a “g” after the last forward slash. The “g” stands for “global”, which tells Perl to replace all matches, and not just the first one.


2 Answers

I need to pass a regex substitution as a variable

Do you? Why not pass a code reference? Example:

sub modify {   my($text, $code) = @_;   $code->($text);   return $text; }  my $new_text = modify('foo baz', sub { $_[0] =~ s/foo/bar/ }); 

In general, when you want to pass "something that does something" to a subroutine ("a regex substitution" in the case of your question) the answer is to pass a reference to a piece of code. Higher Order Perl is a good book on the topic.

like image 162
John Siracusa Avatar answered Oct 25 '22 11:10

John Siracusa


sub proc {     my($match, $subst) = @_;     my $txt = "foo baz";     $txt =~ s/$match/$subst/;     print "$txt\n"; }  my $matcher = qr/foo/; my $sub_str = "bar";  proc($matcher, $sub_str); 

This rather directly answers your question. You can do more - but when I used a qr// term instead of the $sub_str as a simple literal, then the expanded regex was substituted.

I recently needed to create a parser (test parser) for statements with some peculiar (dialect of) SQL types, recognizing lines such as this, splitting it into three type names:

input: datetime year to second,decimal(16,6), integer 

The script I used to demo this used quoted regexes.

#!/bin/perl -w use strict; while (<>) {     chomp;     print "Read: <$_>\n";     my($r1) = qr%^input\s*:\s*%i;     if ($_ =~ $r1)     {         print "Found input:\n";         s%$r1%%;         print "Residue: <$_>\n";         my($r3) = qr%(?:year|month|day|hour|minute|second|fraction(?:\([1-5]\))?)%;         my($r2) = qr%                         (?:\s*,?\s*)?   # Commas and spaces                         (                             (?:money|numeric|decimal)(?:\(\d+(?:,\d+)?\))?   |                             int(?:eger)?  |                             smallint      |                             datetime\s+$r3\s+to\s+$r3                         )                     %ix;         while ($_ =~ m/$r2/)         {             print "Got type: <$1>\n";             s/$r2//;         }         print "Residue 2: <$_>\n";     }     else     {         print "No match:\n";     }     print "Next?\n"; } 

We can argue about the use of names like $r1, etc. But it did the job...it was not, and is not, production code.

like image 34
Jonathan Leffler Avatar answered Oct 25 '22 12:10

Jonathan Leffler