Home > Net >  Calling a function as part of re.sub in Python "eval equivalent in perl"
Calling a function as part of re.sub in Python "eval equivalent in perl"

Time:08-08

I need to be able to call a function in a pattern matching statement with the matched patterned as argument and use the return result of the function as replacement for the matched pattern. In perl, one can use eval function to do that. Here is the perl example:

test =~ s/(>?,)(\d )/eval q{&sum($1,$2)}/ge;

How can I do this in Python. Thanks for your help.

CodePudding user response:

Python's parallel to Perl's eval EXPR is also named eval.

To be more specific,

eval( $code )

is equivalent to

DOLLAR_AT = None      # Global var $@

def perl_eval( code ):
   try:
      DOLLAR_AT = None
      return eval( code )
   catch BaseException as err:
      DOLLAR_AT = err

perl_eval( code )

But you're actually asking about the parallel of /e. This is what allows the replacement expression to be a Perl expression. In Python, similar results can be achieved by passing a function for re.sub's second parameter.

$test =~ s/(\d )\ (\d )/ $1   $2 /eg;

is equivalent to

test = re.sub( r"(\d )\ (\d )", lambda _: str( int( _.group(1) )   int( _.group(2) ) ), test )

Now, let's look at the code you posted. We don't care about $@ here, so the Python equivalent of

$test =~ s/(>?,)(\d )/ eval q{sum( $1, $2 )} /ge;

is

import re

def replacer( match ):
   try:
      return eval( "sum("   match.group(1)   ", "   match.group(2)   ")" )
   except:
      return None

test = re.sub( r"(>?,)(\d )", replacer, test )

[Missing: The Perl snippet warns when the replacement expression returns None.]


That said, this use of eval is completely wrong.

Because sum(>,123) is not valid Perl, the Perl snippet is equivalent to

$test =~ s/(>)?,(\d )/ defined( $1 ) ? undef : eval { sum( $2 ) } /ge;

or

import re

def replacer( match ):
   if match.group(1) is None:
      return None
   else
      try:
         return sum( match.group(2) )
      except:
         return None

test = re.sub( r"(>)?,(\d )", replacer, test )

[Missing: The Perl snippet warns when the replacement expression returns None.]

[Python's parallel to eval BLOCK is try.]

This makes absolutely no sense. The following is probably closer to the author's intentions:

$test =~ s/(>?,)(\d )/ sum( $1, $2 ) /ge;

or

import re
  
test = re.sub( r"(>?,)(\d )", lambda _ : sum( _.group(1), _.group(2) ), test )

That might not be it. Passing >, or , to a sub named sum doesn't seem right. But without knowing what sum does and what the snippet is supposed to do, I can't comment further.

CodePudding user response:

Here is a link to a post that shows how one can call functions in re;sub in Python! Use of functions in re.sub

  • Related