in reply to How do I avoid double substitution when replacing many patterns?

Why not just combine the two into one regexp, skirting the issue entirely?

$phrase = '$foo $(bar)'; $variables = { foo => '$(bar)', bar => '$(foo)' }; $phrase =~ s/ (?: # Just take the first one \$([a-zA-Z0-9_]+) ) | # And alternate it with the second (?: \$\(([a-zA-Z0-9_]+)\) ) /$variables->{$1||$2}/xg; # Then do the substitution for the one # that matched print $phrase; # Prints "$(bar) $(foo)"

I'm sure there's an easier and more efficient way to write this regex, but this seems like the straightforward solution. You eliminate the second pass, so you eliminate the double interpolation. This particular scheme fails if you allow a variable named '0' though, so you may need to do something else in the replacement part if this is the case.

-- David Irving
  • Comment on Re: How do I avoid double substitution when replacing many patterns?
  • Download Code

Replies are listed 'Best First'.
Re^2: How do I avoid double substitution when replacing many patterns?
by diotalevi (Canon) on Jan 20, 2007 at 18:04 UTC

    The leading $and the middle \w are common between patterns. In fact, all that's required is to require a closing ) only when there was an opening (.

    Using a less well known feature

    \$ # Our '$' prefix (?: # Optionally *don't* find the opening paren. | (\() # Optionally find the opening paren ) (\w+) # The middle part is captured in $2 (?(1)\)) # Require a closing paren only if $1 matched.

    Merely removing the prefix

    \$ # Our '$' prefix ( # Capture into $1 (?: \w+ # Plain word. | \( \w+ \) # A word with parentheses around it. ) )

    ⠤⠤ ⠙⠊⠕⠞⠁⠇⠑⠧⠊

      You could change
      (?: | ( \( ) )
      to
      ( \( )?
      ... unless you get queasy when you see quantifiers placed on capturing groups.

      Jeff japhy Pinyan, P.L., P.M., P.O.D, X.S.: Perl, regex, and perl hacker
      How can we ever be the sold short or the cheated, we who for every service have long ago been overpaid? ~~ Meister Eckhart

        I thought about it but decided I wasn't sure whether that would work correctly with the later conditional. If it does, great.

        ⠤⠤ ⠙⠊⠕⠞⠁⠇⠑⠧⠊

Re^2: How do I avoid double substitution when replacing many patterns?
by bart (Canon) on Jan 21, 2007 at 07:51 UTC
    Replace $1 ||$2 with $+. That'll contain the value of the last capture that actually matched. See perlvar:
    The text matched by the last bracket of the last successful search pattern. This is useful if you don't know which one of a set of alternative patterns matched.

    p.s. Originally I mistakingly had posted this as a followup to Re^2: How do I avoid double substitution when replacing many patterns?, now its sibling.

      PS, I didn't know about $+ so I'm glad you posted that in the wrong place.

      ⠤⠤ ⠙⠊⠕⠞⠁⠇⠑⠧⠊

Re^2: How do I avoid double substitution when replacing many patterns?
by kyle (Abbot) on Jan 20, 2007 at 19:13 UTC

    This particular scheme fails if you allow a variable named '0' though, so you may need to do something else in the replacement part if this is the case.

    Yes. In that case, your "$1||$2" would have to be "defined $1 ? $1 : $2".