in reply to Re: Function call in regex replacement string
in thread Function call in regex replacement string

:-)

Yes.. I thought about both the /e and eval ( :-o ) approaches, but they do not satisfy my needs... let me try and clarify:

I want to provide the replacement string as a configurable parameter and not embedded within the search - replace code.

I would like to have :
for (@array) { s/HAI WORLD Times ([0-9]+).*/ '\t\t<exML LOLZ = "' . $replacement->($1) . '"/>' /eg; }

as
for (@array) { s/$searchString/$replaceString/g; }


Um.. does that make sense?

Replies are listed 'Best First'.
Re^3: Function call in regex replacement string
by tilly (Archbishop) on Feb 24, 2009 at 10:02 UTC
    What you're asking for won't work without a bunch of magic. If you really, really want it to look like that, create an object with an overload that causes it to do something particular when you stringify it. If you do that, though, then don't blame me if the maintenance programmer turns out to be a psychopath with an axe who knows where you live.

    However the following can work and at least gives a hint as to the evil lurking within:

    for (@array) { s/$searchString/$replaceString/eeg; }
    Where the ee means you eval it, and then eval the result of that. Or in other words you execute whatever is in $replaceString as code. I would set that up more sanely as:
    for (@array) { s/$searchString/$replace->()/eg; }
    But then again I'm a sane sort of guy who doesn't want to worry about maintenance programmers on a vendetta.
      Hi tilly,

      My requirement is exactly what the attached program behaves like - only thing I did not want to use in my program was eval.

      In the end, unfortunately, eval seems the only way out. I did not want it to be (I pointed out in the very beginning that eval would work but was not preferred).

      Maintainance would be an issue, but then this approach would do away with people grepping through the source and locate the replacement expressions .. how useful is that too from the maintainance point of view?

      With the horrific approach below, you can very well put the replacement string in an external config file and keep such things separate from the main program... in my view that is more maintainable... would you (or anyone else) not agree?

      Why would anyone keep configurable things embedded in the logic/source code?

      use strict; use warnings; use Data::Dumper; use Tie::File; # open the file if it exists, but fail if it does not exist use Fcntl 'O_RDWR'; our @array = (); our $file = 'hai'; tie @array, 'Tie::File', $file, mode => O_RDWR or die $!; our $SearchString = 'HAI WORLD Times ([0-9]+).*$'; our $ReplaceString = '"\t\t<exML LOLZ = \"" . unpack(\'a1\', $1) . "\" +/>"'; my $elementIdx = 0; while($elementIdx <= $#array) { if($array[$elementIdx] =~ $SearchString) { # Maintain only the first character $array[$elementIdx++] = eval $ReplaceString; } else { splice @array, $elementIdx, 1; # we don't want this in the output } } untie @array; # all done!
        You ask why people would keep configurable things in source code? Well every time you try to pull configurable things out you pay the following costs:
        • Code does not magically become non-code by being moved to a configuration file. And the more you move there, the harder it becomes to read. I could submit many Apache config files for examples.
        • You have to add a layer of indirection to your code, making it harder to understand. Your code example is a demonstration.
        • You increase how much "action at a distance" there is. Action at a distance makes code harder to read, errors harder to spot, and synchronization errors much more common.
        This is not to say that moving stuff into configuration is necessarily bad. In fact it is good if you need to tweak that configurable thing frequently.

        With that said, your program is the same as:

        #! /usr/bin/perl -ni BEGIN { @ARGV = my $file = "hai"; die "File '$file' doesn't exist!" unless -e $file; } print if s/HAI WORLD Times ([0-9]+).*/ "\t\t<exML LOLZ = \"" . unpack(\'a1\', $1) . "\" />" /eg;
        Yeah, it is a hack. But which hack would you prefer to maintain?

        And a random note. Rather than eval you can just use a closure:

        $replaceString = sub { "\t\t<exML LOLZ = \"" . unpack(\'a1\', $1) . "\" />" }; # time passes $array[$elementIdx++] = $replaceString->();
        This has a number of advantages, including much better performance, and the fact that errors are not accidentally trapped. (Trust me, if you're evaling code from a configuration, you want to know if the configuration is bad.)