Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

I want to substitute values for named constants in some text. The solution I have is:
my $constant; for $constant (keys %constants) { $line =~ s/$constant/$constants{$constant}/g; }
The problem is that this is very slow.

Replies are listed 'Best First'.
RE: How do I speed this up?
by chromatic (Archbishop) on Mar 24, 2000 at 23:30 UTC
    This looks to be about 10% faster on my dataset:
    foreach my $constant (keys %constants) { $string = join $constants{$constant}, split /$constant/, $string; }
    It's a lot less clear, though. Maybe if you build the regexes beforehand, you'll see a speed benefit? Look at the qr/// operator.
Re: How do I speed this up?
by stephen (Priest) on Feb 26, 2000 at 05:54 UTC
    Hmmm....

    If you're doing this repeatedly you can use my Text::Boilerplate module.
    http://www.perl.com/CPAN-local//authors/id/S/ST/STEPHEN/Text-Boilerplate-0.08.tar.gz

    Boilerplate will let you put things like Foo is [* "foo" *] in your text and will generate an anonymous sub to turn this template into text. It avoids re-doing the replace every time, that way. Of course, you do pay the penalty of doing the original processing...

    Otherwise, you can try Text::Vpp.

    Hmm... another possibility, similar to above ones... I don't know whether this will speed things up, slow them down, or even work at all, but try it:

    %constants = ( 'foo' => 'bar', 'baz' => 'bap' ); $pattern = join('|', map(quotemeta($_), keys %constants) ); eval("s{($pattern)}{\$constants{\$1)}e");

    stephen

RE: How do I speed this up?
by Anonymous Monk on Feb 25, 2000 at 22:18 UTC
    Uh, that code has too many $contsant's. Let's see... How about code that generates code (always fun!)
    # # Generate regex code from hash (untested) # my $code; foreach my $key (keys %const_hash) { $code .= qq( \$const =~ s/$key/$$const_hash{$key}/;\n ); } my $const = 'fill string here'; eval $code; die $@ if $@; # die on error
    dwatson@netcom.com
Re: How do I speed this up?
by btrott (Parson) on Feb 25, 2000 at 23:38 UTC
    Look at perlman:perlfaq6 for the section "How do I efficiently match many regular expressions at once?"

    Another option is to build a regular expression like this:

    s/(foo|bar|baz)/$constants{$1}/g;
    where "foo", "bar", and "baz" are your constants, the keys in your %constants hash. You'll want to use \Q and \E around each of the constants if they contain any regexp metacharacters.
Re: How do I speed this up?
by btrott (Parson) on Feb 25, 2000 at 23:46 UTC
    I should have also noted that, if you build such a regular expression, you can then eval it to do the replacements.