Problem s replace

Honza Pazdziora adelton na fi.muni.cz
Pátek Únor 4 09:49:57 MET 2000


On Thu, 3 Feb 2000 18:07:54 GMT, Zdenek Kabelac <kabi na fi.muni.cz> wrote:
> Ahojky
> 
> Poradi me zde nekdo s tim, jak tento
> vcelku jednoduchy script napsat spravne tak, aby fungoval
> (chci to mit jako subrutinu - samozrejme
> pokud napisu vse v jednom radku tak to funguje)
> 
> Jde me o to, jak predat do subrutinu parametry tak,
> aby se spravne provedl replace

Preposilam odpoved od Toma Phoenixe, ktere se mi dostalo, kdyz jsem
ten samy dotaz polozil pred tremi lety ;-)

From: Tom Phoenix <rootbeer na teleport.com>
To: Honza Pazdziora <adelton na informatics.muni.cz>
Subject: Re: Passing pattern for subst to function
Message-Id: <Pine.SUN.3.92.961201114354.20548A-100000 na linda.teleport.com>
Date: Sun, 1 Dec 1996 12:52:05 -0800 (PST)

I think that the trouble you're having starts because the two halves of
the s/// are not symmetrical. The left side is interpolated (that is, the
current value of $pattern is put into it), then treated as a pattern,
which is doing what you want.
  
But the right side is simply a string. This is the kind of string we call
"double-quotish" because it acts like a double-quoted string acts. In
particular, it interpolates $replace, giving the string '$2x$1'. I think
you want that to be interpolated as well, but that's not something Perl
normally does.
  
Perl offers an unusual feature which may help, but there's a catch. If you
add the /e option, you can actually use an expression, rather than just a
double-quotish string, on the right side of the s/// operator. Now the
expression that you pass to your sub can be changed to '"$2x$1"', with an
extra set of double quotes added. But we're not done yet.
  
This is the unusual feature I mentioned earlier: If you put TWO e's on,
the expression is evaluated twice. That is, it's evaluated, then the
result of that evaluation is evaluated again! This is tricky enough that
I've shown the stages here.

        cx7             The original matched string (an example)
        $replace        The right side of the s///
        "$2x$1"         After evaluation once
        7xc             After evaluation twice

The value on the third line is the same to Perl as this expression below,
so evaluating it does what you wanted. (This is why the double quotes were
needed.)

        $2 . 'x' . $1

So, if you type in "abcx789" to the first attached script, you'll get back
"ab7xc89". Is that what you would want? (If you'd reversed the $1 and $2  
in your example, I'd wonder whether you wanted to use Perl's x operator to
replicate the string.)

Here's the catch. Now you'll have to prepare every replacement string for
this extra step of double-evaluation. (In fact, each one will need to be 
valid Perl code, and perl will do whatever they ask!) For example, if you
want the replacement string to be 'FOO', you have to pass it as '"FOO"'  
(that is, the double quotes are part of the string, but the single quotes
aren't).

If you pass the string 'time' as the replacement, perl will put in the
system time integer. And if you pass '`date`', perl will call the system
command date(1) and put its return value into your string! This is one of
the situations in which, as I like to say, "Perl is the kind of language 
which gives you enough rope to shoot yourself in the foot." It'll do
whatever you ask, whether that's what you want or not. (This could be very
dangerous if the replacement string is unknown until runtime, since it
could potentially erase files or cause other damage to your system. For
that matter, if it isn't valid Perl it can cause strange error messages.)

So what's the solution? If you're going to need to determine the
replacement value as an expression at runtime, you'll have a lot to worry
about. But if you just want to pass a bit of code into a sub, the second 
attachment might be what you want. It uses references to pass a piece of 
code, as a subroutine, into the subroutine, so it's a little confusing,  
perhaps. But it's also "cleaner". This sort of thing is documented in the
new Camel and in perlref(1).

I've given you a lot here, and I hope it's not too overwhelming. I'm not
sure how helpful it will be, either, because I don't know more about what
you're trying to do, so I've made some guesses here. I hope that some of 
what I've written will help to put you on the right track, but if you have
more questions, please feel free to write again!

-- Tom Phoenix        http://www.teleport.com/~rootbeer/
rootbeer na teleport.com   PGP  Skribu al mi per Esperanto!
Randal Schwartz Case:     http://www.lightlink.com/fors/

#!/usr/bin/perl -w

sub user_subst
        {
        my ($pattern, $replace) = @_;
        print "$pattern -> $replace\n";
        s/$pattern/$replace/ee;
        print "1 = $1, 2 = $2\n";
        print;
        }
         
while (<>)
        { 
        user_subst('([a-z])x([0-9])', '"$2x$1"');
        }
         
__END__  

#!/usr/bin/perl -w

sub user_subst
        {
        my ($search, $subroutine) = @_;
        s/$search/ &$subroutine /e;
                        # Calling the referenced subroutine
        print;
        }
         
while (<>)
        { 
            user_subst(
                '([a-z])x([0-9])', sub { "$2x$1" }
            );
        }
         
__END__  

-- 
------------------------------------------------------------------------
 Honza Pazdziora | adelton na fi.muni.cz | http://www.fi.muni.cz/~adelton/
   .project: Perl, DBI, Oracle, MySQL, auth. WWW servers, MTB, Spain.
------------------------------------------------------------------------


Další informace o konferenci Perl