Captuerd Text as Variable in Search-Operation

P

pk

Hi!

If I do a search an have parenthesis in the search string, I've got
the "captuered" text in the special variables $1, $2 ... My problem
is: I want to pass the search + replace-text as variables and work
with the "captured" text (some user enters the search- +
replace-text); for exampel like that:

$serach_string = "(.*)XXX(.*);
$replace_string = "$1---$1";

$line =~ /$serach_string/;
$new_line = $replace_string;

If $line would be aaaXXXbbb , $new_line should be aaa---bbb .

But I can't use $1 etc. Is there any possibility to get the "captured"
text?

pk
 
W

Walter Roberson

:If I do a search an have parenthesis in the search string, I've got
:the "captuered" text in the special variables $1, $2 ... My problem
:is: I want to pass the search + replace-text as variables and work
:with the "captured" text (some user enters the search- +
:replace-text); for exampel like that:

:$serach_string = "(.*)XXX(.*);
:$replace_string = "$1---$1";

If the user has control over these expressions, you are going to
have to be careful, as the user might put in ${text} to cause
that text to be executed by you.

:$line =~ /$serach_string/;
:$new_line = $replace_string;

:If $line would be aaaXXXbbb , $new_line should be aaa---bbb .

Not unless the $replace_string were '$1---$2' instead.


:But I can't use $1 etc. Is there any possibility to get the "captured"
:text?

I do not know why you say you cannot use $1 etc. but you do not
seem to need to.

$line =~ s/$search_string/$replace_string/;

But look back to what you had earlier:

$replace_string = "$1---$1";

For the code I gave to work, you would instead need to use:

$replace_string = '$1---$2';

Notice the single-quotes instead of the double-quotes. When you have
the double-quotes, the $1 and $2 will be interpolated at the time
the variable is set. You want the $1 and $2 to be treated literally
until they are encountered in the context of the s/// .
 
G

gnari

pk said:
If I do a search an have parenthesis in the search string, I've got
the "captuered" text in the special variables $1, $2 ... My problem
is: I want to pass the search + replace-text as variables and work
with the "captured" text (some user enters the search- +
replace-text); for exampel like that:

$serach_string = "(.*)XXX(.*);
$replace_string = "$1---$1";

$line =~ /$serach_string/;
$new_line = $replace_string;

If $line would be aaaXXXbbb , $new_line should be aaa---bbb .

actually it would be aaa---aaa
But I can't use $1 etc. Is there any possibility to get the "captured"
text?

take a look at the /e modifier of s///
perdoc perlop
you can do what you want with /ee
but you have to think about what you are doing
s/$serach_string/'"'.$replace_string.'"'/ee;

you should ABSOLUTELY NOT do this if
$serach_string is not trusted.

gnari
 
G

gnari

[snipped regexp problem w/ variable replace w/ captures]

[snipped solution involving /ee]

I regret having posted the /ee solution.

here is a solution that is safer:

$serach_string = '(.*)XXX(.*)';
$replace_string = '$1---$2';
$line='aaaXXXbbb';

my @cap=(undef,/$serach_string/);
(my $r=$replace_string)=~s/\$(\d)/$cap[$1]/g;
$line=~s/$serach_string/$r/g;
 
B

Ben Morrow

gnari said:
here is a solution that is safer:

You would need to wrap both matches in eval{} to catch the possible
'Eval-group not allowed at runtime' error.
$serach_string = '(.*)XXX(.*)';
$replace_string = '$1---$2';
$line='aaaXXXbbb';

my @cap=(undef,/$serach_string/);

ITYM my @cap = (undef, $line =~ /$serach_string/);
(my $r=$replace_string)=~s/\$(\d)/$cap[$1]/g;

I would have \d+ here...?
$line=~s/$serach_string/$r/g;

Ben
 
G

gnari

Ben Morrow said:
You would need to wrap both matches in eval{} to catch the possible
'Eval-group not allowed at runtime' error.


ITYM my @cap = (undef, $line =~ /$serach_string/);

yep. I started with $_ but changed to $line
to conform with the original post and missed this one
(my $r=$replace_string)=~s/\$(\d)/$cap[$1]/g;

I would have \d+ here...?

I was wondering if someone would mention this :)

gnari
 
R

Robin

If I do a search an have parenthesis in the search string, I've got
the "captuered" text in the special variables $1, $2 ... My problem
is: I want to pass the search + replace-text as variables and work
with the "captured" text (some user enters the search- +
replace-text); for exampel like that:

$serach_string = "(.*)XXX(.*);

for one thing, this doesn't have it's quote at the end...
 
B

Brian McCauley

[ posted and accidently mailed also - oops ]

If I do a search an have parenthesis in the search string, I've got
the "captuered" text in the special variables $1, $2 ... My problem
is: I want to pass the search + replace-text as variables and work
with the "captured" text (some user enters the search- +
replace-text); for exampel like that:

$serach_string = "(.*)XXX(.*);
$replace_string = "$1---$1";

$line =~ /$serach_string/;
$new_line = $replace_string;

If $line would be aaaXXXbbb , $new_line should be aaa---bbb .

But I can't use $1 etc. Is there any possibility to get the "captured"
text?

Y'know, this is the most frequently asked single question not
currently in the Perl FAQ.

In some senses it's really just a special case of the existing FAQ
"How can I expand variables in text strings?" but the s/// question
actually appears more often the the general case so I think it
probably warrants its own entry. Anyhow I've always disliked the
answer given in the FAQ to "How can I expand variables in text
strings?" because I think it's incomplete.

Anyhow for more suggestions than you could shake a stick at see dozens
(hundreds?) previous threads asking the exact same question. Sooner
or later in any such thread someone is pretty-much sure to mention the
FAQ "How can I expand variables in text strings?" so searching on that
phrase should pick up pretty-much all such threads.

--
\\ ( )
. _\\__[oo
.__/ \\ /\@
. l___\\
# ll l\\
###LL LL\\
 
A

Anno Siegel

gnari said:
[snipped regexp problem w/ variable replace w/ captures]

[snipped solution involving /ee]

I regret having posted the /ee solution.

here is a solution that is safer:

$serach_string = '(.*)XXX(.*)';
$replace_string = '$1---$2';
$line='aaaXXXbbb';

my @cap=(undef,/$serach_string/);

Should be

my @cap=(undef,$line =~ /$search_string/);

as has been noted.
(my $r=$replace_string)=~s/\$(\d)/$cap[$1]/g;
$line=~s/$serach_string/$r/g;

That does the job, but I find it a little hard to see how it does it.
This may be more readable:

# keep whatever the user's pattern captures (to put it back in later)
my @stick_back_in = $line =~ /$search_string/;

#do the replacement literally
$line =~ s/$search_string/$replace_string;

# now $line has literal "$1", "$2", etc. in it. Replace them
# one by one with the original text they captured
$line =~ s/\$\d+/shift @stick_back_in/eg;

Anno
 
P

pk

gnari said:
actually it would be aaa---aaa


take a look at the /e modifier of s///
perdoc perlop
you can do what you want with /ee
but you have to think about what you are doing
s/$serach_string/'"'.$replace_string.'"'/ee;

you should ABSOLUTELY NOT do this if
$serach_string is not trusted.

gnari


Hi gnari,

thanks a lot !!! This looks like what i've been searching for!

# These are the arguments on the command-line:
my $line = $ARGV[0]; # aaaXXXbbb
my $search = $ARGV[1]; # '(.*)XXX(.*)'
my $replace = $ARGV[2]; # '$1---$2'

$line =~ s/$search/'"'.$replace.'"'/ee;

print "$line\n"; # And this is the result: aaa---bbb
# exactly what i wanted!

Solong: pk
 
P

pk

gnari said:
[snipped regexp problem w/ variable replace w/ captures]

[snipped solution involving /ee]

I regret having posted the /ee solution.

here is a solution that is safer:

$serach_string = '(.*)XXX(.*)';
$replace_string = '$1---$2';
$line='aaaXXXbbb';

my @cap=(undef,/$serach_string/);
(my $r=$replace_string)=~s/\$(\d)/$cap[$1]/g;
$line=~s/$serach_string/$r/g;

Hi gnari,

thanks again! But this does not work ...

# These are the arguments on the command-line:
my $line = $ARGV[0]; # aaaXXXbbb
my $search = $ARGV[1]; # '(.*)XXX(.*)'
my $replace = $ARGV[2]; # '$1---$2'


my @cap=(undef,/$search/);
(my $r = $replace) =~ s/\$(\d+)/$cap[$1]/g;
$line =~ s/$search/$r/g;

print "$line\n";


# prints out:
#
# Use of uninitialized value in pattern match (m//) at ./my_regex_02.pl line 12.
# Use of uninitialized value in substitution iterator at ./my_regex_02.pl line 14.
# Use of uninitialized value in substitution iterator at ./my_regex_02.pl line 14.
# ---

Solong: pk
 
G

gnari

Anno Siegel said:
gnari said:
"gnari" <[email protected]> wrote in message
(my $r=$replace_string)=~s/\$(\d)/$cap[$1]/g;
$line=~s/$serach_string/$r/g;

That does the job, but I find it a little hard to see how it does it.
This may be more readable:

# keep whatever the user's pattern captures (to put it back in later)
my @stick_back_in = $line =~ /$search_string/;

#do the replacement literally
$line =~ s/$search_string/$replace_string;

assuming you add the third / of the s///
# now $line has literal "$1", "$2", etc. in it. Replace them
# one by one with the original text they captured
$line =~ s/\$\d+/shift @stick_back_in/eg;

well, I had thought about that, but what if the original
$line contains literal $n ?

gnari
 
P

pk

gnari said:
[snipped regexp problem w/ variable replace w/ captures]

[snipped solution involving /ee]

I regret having posted the /ee solution.

here is a solution that is safer:

$serach_string = '(.*)XXX(.*)';
$replace_string = '$1---$2';
$line='aaaXXXbbb';

my @cap=(undef,/$serach_string/);
(my $r=$replace_string)=~s/\$(\d)/$cap[$1]/g;
$line=~s/$serach_string/$r/g;



Hi gnari,

sorry, my first answer was without that i have already been reading
the comment to your code. It does the work very well and for me it is
a good example for the power of Perl (if you know what you are doing).
What i think i understand is:

@cap = ( $line =~ /$search/) # $cap[0] is what is found with the
# first paranthesis; i was already
# playing around with that for a while;
# but it took me lots of lines to _not_
# succeed. Including the 'undef'
# $cap[0] is not defined. I thing you
# do this, to have the correct index
# for $cap[] in the next line
(my $r=$replace) =~ s/\$(\d+)/$cap[$1]/g; # You search any literal
# $1, $2 ... (so \d+ makes
# sense - but this could become quite a
# monster of regexp ... ) and replace
# that with the corresponding $cap[].
# Without the () around '$r=$replace',
# '$r' holds the number of substituti-
# ons (right?) but what do the () do ?
# And: with the (), '$r' already holds,
# what is later on found on $line ...
# (at least with the examples, i tried)
$line =~ s/$search/$r/g; # - so why that third line of code?


Again, hanks for your help!

bye: pk
 
B

Ben Morrow

[comments rearranged somewhat]

What i think i understand is:

@cap = (undef, $line =~ /$search/)
^^^^^ gnari's undef put back in
# $cap[0] is what is found with the first paranthesis; i was already
# playing around with that for a while; but it took me lots of lines
# to _not_ succeed. Including the 'undef' $cap[0] is not defined. I
# thing you do this, to have the correct index for $cap[] in the
# next line

This is right. The expression ($line =~ /$search/) returns a list of
all the bracketed expressions in the match, the initial 'undef' makes
sure that the first is in $cap[1] not $cap[0].
(my $r=$replace) =~ s/\$(\d+)/$cap[$1]/g;
# You search any literal $1, $2 ... (so \d+ makes sense - but this
# could become quite a monster of regexp ... )

This is hardly large :). When regexen get large and nasty, I find it
really helps to use the /x switch (read perldoc perlre) and to break
it up into bits in variables (with qr), so I can give them meaningful
names.
# and replace that with the corresponding $cap[].
# Without the () around '$r=$replace', '$r' holds the number of
# substitutions (right?)

Yes, that's right. What the brackets do is change the order of
evaluation, so the statement is equivalent to:

my $r = $replace;
$r =~ s/..../g;

There are some slightly subtle concepts here: (my $r = $replace) is an
expression (unlike in some other languages), and therefore it has a
value; the value it has is $r. So the pattern match is then applied to
that value, and the replacement is done on $r.
# but what do the
# () do ? And: with the (), '$r' already holds, what is later on
# found on $line ... (at least with the examples, i tried)

$line =~ s/$search/$r/g; # - so why that third line of code?

What you failed to try is something like the following:

$line = "aaa--BBB--";
$search = "--(.*)--";
$replace = '==$1==';

After you execute the code above, $r will be "==BBB==", but $line will
be "aaa==BBB==".

Ben
 
A

Anno Siegel

gnari said:
Anno Siegel said:
gnari said:
"gnari" <[email protected]> wrote in message
(my $r=$replace_string)=~s/\$(\d)/$cap[$1]/g;
$line=~s/$serach_string/$r/g;

That does the job, but I find it a little hard to see how it does it.
This may be more readable:

# keep whatever the user's pattern captures (to put it back in later)
my @stick_back_in = $line =~ /$search_string/;

#do the replacement literally
$line =~ s/$search_string/$replace_string;

assuming you add the third / of the s///

Ugh, where did that go? It was there when I ran the code :)
well, I had thought about that, but what if the original
$line contains literal $n ?

....or if the replacement introduces them? Then it goes wrong, but
so does yours in a quick test. The OP didn't seem overly concerned
about this kind of robustness, so I thought, why bring it up? :)

Anno
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,764
Messages
2,569,564
Members
45,039
Latest member
CasimiraVa

Latest Threads

Top