Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Perl > Perl Misc > search/replace values from an array - Part 2.

Reply
Thread Tools

search/replace values from an array - Part 2.

 
 
Sandman
Guest
Posts: n/a
 
      08-02-2004
Hello again, and thanks to Anno Siegel for your answer to my earlier thread
(news:(E-Mail Removed)) on the subject, but
unfortunately, the conditions for my need has slightly altered, and I want some
further help (from anyone, not just Anno).


Here is a code snippet that probably illustrates what I want to do:

-------------
#!/usr/bin/perl
use strict;
use warnings;

my $string = "Hello World!";

my %array = (
"Hello (.*?)!", "Goodbye, little #1#!"
# search reply
);
foreach (keys %array){
if ($string=~m/$_/i){
# It matched!

$array{$_}=~s/#(\d+)#/$$1/;
# replace #1# with $1, #2# with $2
# from the match above

print "$string\n\n";
print "$array{$_}\n\n";
# Add the reply to the string
}
}
-------------

Wanted output:

Hello World!

Goodbye, little World!

So, as opposed to my earlier thread, I no longer seek to replace the original
string, but rather add a "reply" to it, if it matches. Basically, what I want
to do is replace the string #1#, #2#, #3#... with the values in $1, $2, $3...
but when trying to do that, perl complains about:

File "test.pl"; Line 15: Can't use string ("1") as a SCALAR ref while
"strict refs" in use

Line 15 being:

$array{$_}=~s/#(\d+)#/$$1/;

Thanks for any help.

--
Sandman[.net]
 
Reply With Quote
 
 
 
 
Anno Siegel
Guest
Posts: n/a
 
      08-02-2004
Sandman <(E-Mail Removed)> wrote in comp.lang.perl.misc:
> Hello again, and thanks to Anno Siegel for your answer to my earlier thread
> (news:(E-Mail Removed)) on the subject, but
> unfortunately, the conditions for my need has slightly altered, and I want some
> further help (from anyone, not just Anno).
>
>
> Here is a code snippet that probably illustrates what I want to do:
>
> -------------
> #!/usr/bin/perl
> use strict;
> use warnings;
>
> my $string = "Hello World!";
>
> my %array = (
> "Hello (.*?)!", "Goodbye, little #1#!"
> # search reply
> );
> foreach (keys %array){
> if ($string=~m/$_/i){
> # It matched!
>
> $array{$_}=~s/#(\d+)#/$$1/;


Well, this doesn't do what you hope it does. You knew that, and I
showed you a way to do the replacements. Why are you trying it again?

> # replace #1# with $1, #2# with $2
> # from the match above
>
> print "$string\n\n";
> print "$array{$_}\n\n";
> # Add the reply to the string


What does that mean? Append it?

> }
> }
> -------------
>
> Wanted output:
>
> Hello World!
>
> Goodbye, little World!
>
> So, as opposed to my earlier thread, I no longer seek to replace the original
> string, but rather add a "reply" to it, if it matches.


Trivial. Copy the original, modify the copy, concatenate both.

> Basically, what I want
> to do is replace the string #1#, #2#, #3#... with the values in $1, $2, $3...
> but when trying to do that, perl complains about:
>
> File "test.pl"; Line 15: Can't use string ("1") as a SCALAR ref while
> "strict refs" in use
>
> Line 15 being:
>
> $array{$_}=~s/#(\d+)#/$$1/;


I've shown a way to do that in my earlier reply. Your changed
requirements have nothing to do with how to achieve this, you'd have
to do it in any case. So, apply my solution (or another one) to the
new situation. Don't go back to square one, just because an irrelevant
detail has changed.

Anno
 
Reply With Quote
 
 
 
 
Gunnar Hjalmarsson
Guest
Posts: n/a
 
      08-02-2004
Sandman wrote:
>
> #!/usr/bin/perl
> use strict;
> use warnings;
>
> my $string = "Hello World!";
>
> my %array = (


Funny name of a hash.

> "Hello (.*?)!", "Goodbye, little #1#!"
> # search reply
> );
> foreach (keys %array){
> if ($string=~m/$_/i){
> # It matched!
>
> $array{$_}=~s/#(\d+)#/$$1/;
> # replace #1# with $1, #2# with $2
> # from the match above


Besides that you are trying to use a symbolic (or soft) reference,
which is normally not advisable, you are assuming that the $1 variable
contains what was captured from both the last and the previous
matches, and that appears to be somewhat optimistic...

You need to store what was captured from the first match somewhere,
i.e. in a hash:

my %captures = (
1 => $1,
);
$array{$_} =~ s/#(\d+)#/$captures{$1}/;

> print "$string\n\n";
> print "$array{$_}\n\n";
> # Add the reply to the string
> }
> }
> -------------
>
> Wanted output:
>
> Hello World!
>
> Goodbye, little World!


--
Gunnar Hjalmarsson
Email: http://www.gunnar.cc/cgi-bin/contact.pl
 
Reply With Quote
 
Sandman
Guest
Posts: n/a
 
      08-02-2004
In article <cel5b7$66f$(E-Mail Removed)-Berlin.DE>,
http://www.velocityreviews.com/forums/(E-Mail Removed)-berlin.de (Anno Siegel) wrote:

> > Hello again, and thanks to Anno Siegel for your answer to my earlier thread
> > (news:(E-Mail Removed)) on the subject, but
> > unfortunately, the conditions for my need has slightly altered, and I want
> > some
> > further help (from anyone, not just Anno).
> >
> >
> > Here is a code snippet that probably illustrates what I want to do:
> >
> > -------------
> > #!/usr/bin/perl
> > use strict;
> > use warnings;
> >
> > my $string = "Hello World!";
> >
> > my %array = (
> > "Hello (.*?)!", "Goodbye, little #1#!"
> > # search reply
> > );
> > foreach (keys %array){
> > if ($string=~m/$_/i){
> > # It matched!
> >
> > $array{$_}=~s/#(\d+)#/$$1/;

>
> Well, this doesn't do what you hope it does. You knew that, and I
> showed you a way to do the replacements. Why are you trying it again?


I'm not, this is just an illustrative script to givbe the gist of what I want
to do, and while your script worked for the purpose of my earlier needs, it
doesn't for these altered needs, so I went back to this script which doesn't
work, but should give the reader an idea of what I want to achieve.

Plus, your script replaced strings, which I no longer wish to do.

> > # replace #1# with $1, #2# with $2
> > # from the match above
> >
> > print "$string\n\n";
> > print "$array{$_}\n\n";
> > # Add the reply to the string

>
> What does that mean? Append it?


Bad wording. The script should output the original string, with the "reply"
printed after it, with #1#, #2#... expanded into the matched values from the
search string.

> > }
> > }
> > -------------
> >
> > Wanted output:
> >
> > Hello World!
> >
> > Goodbye, little World!
> >
> > So, as opposed to my earlier thread, I no longer seek to replace the
> > original string, but rather add a "reply" to it, if it matches.

>
> Trivial. Copy the original, modify the copy, concatenate both.
>
> > Basically, what I
> > want
> > to do is replace the string #1#, #2#, #3#... with the values in $1, $2,
> > $3...
> > but when trying to do that, perl complains about:
> >
> > File "test.pl"; Line 15: Can't use string ("1") as a SCALAR ref while
> > "strict refs" in use
> >
> > Line 15 being:
> >
> > $array{$_}=~s/#(\d+)#/$$1/;

>
> I've shown a way to do that in my earlier reply. Your changed
> requirements have nothing to do with how to achieve this, you'd have
> to do it in any case. So, apply my solution (or another one) to the
> new situation. Don't go back to square one, just because an irrelevant
> detail has changed.


Well, my problem with your earlier script was this (note the altered string):


#!/usr/bin/perl
use strict;
use warnings;


my %tab = (
'Hello (.*?)!' => 'Goodbye, little #1#...',
'Welcome (.*?) and (.*?)!' => 'Farewell, honorable #2# and fair #1#!',
);



for ( "Welcome ladies and gentlemen! Please step inside", "Hello World!" ) {
my $string = $_; # make a copy we can change

while ( my ( $search, $replace) = each %tab ) {
# build ready-to-use replacement string from template
my $n = 1; # submatch number
for ( $string =~ /$search/ ) { # loop over submatches
$replace =~ s/#$n#/$_/g, # substitute one submatch everywhere
$n ++; # next submatch
}
last if $string =~ s/$search/$replace/;
}
print "$string\n";

}

This outputs

Farewell, honorable gentlemen and fair ladies! Please step inside
Goodbye, little World...

Which is undesirable. And, oddly enough, it only worked occasionally with one
specific string (i.e. running the script five times in a row made it match it
two times, highly bizarre).

So, despite your efforts, I felt I wanted to go back to square one and attack
the faulty line in my little script.

Isn't there a way, while using strict refs, to replace #1#, #2#, #3#... with
the values of $1, $2, $3, which are created by a match operation?

--
Sandman[.net]
 
Reply With Quote
 
Sandman
Guest
Posts: n/a
 
      08-02-2004
In article <(E-Mail Removed)>,
Gunnar Hjalmarsson <(E-Mail Removed)> wrote:

> > foreach (keys %array){
> > if ($string=~m/$_/i){
> > # It matched!
> >
> > $array{$_}=~s/#(\d+)#/$$1/;
> > # replace #1# with $1, #2# with $2
> > # from the match above

>
> Besides that you are trying to use a symbolic (or soft) reference,
> which is normally not advisable, you are assuming that the $1 variable
> contains what was captured from both the last and the previous
> matches, and that appears to be somewhat optimistic...
>
> You need to store what was captured from the first match somewhere,
> i.e. in a hash:
>
> my %captures = (
> 1 => $1,
> );
> $array{$_} =~ s/#(\d+)#/$captures{$1}/;


Aaah, this did the trick. Thanks!

--
Sandman[.net]
 
Reply With Quote
 
Anno Siegel
Guest
Posts: n/a
 
      08-02-2004
Sandman <(E-Mail Removed)> wrote in comp.lang.perl.misc:

[big snip]

> Isn't there a way, while using strict refs, to replace #1#, #2#, #3#... with
> the values of $1, $2, $3, which are created by a match operation?


Okay, let's treat this in isolation. Suppose you have:

my $string = 'Hello ladies and gentlemen, please step inside';
my $pattern = 'Hello (.*?) and (.*?),';
my $template = 'Farewell honorable #2# and fair #1#';

To do the replacements in the most straightforward way, you could
try this (broken code ahead):

if ( $string =~ /$pattern/ ) {
$template =~ s/#1#/$1/g;
$template =~ s/#2#/$2/g;
}

This doesn't work because we are trying to use $1 and $2 in a
replacement operation. The pattern match that is the first part of
the replacement will destroy the contents of $1 and $2, so we can't
use them that way.

Another problem is that we don't know, in general, how many of $1, $2,...
will be set by $pattern, so we don't know how many replacement lines to
write.

To get around both problems, we can use the fact that a match in list
context returns the captured submatches. So we can loop over them
without knowing how many there are. This action also de-couples the
list elements from the actual variables $1, $2, ..., which is slightly
magical.

We must now generate the marker strings "#1#", "#2#" dynamically.
So:

my $n = 1;
for ( $string =~ /$pattern/ ) {
$template =~ s/#$n#/$_/g;
$n ++;
}

Now $template has been transformed into the reply. $string is
unchanged. This is (in isolation) the same solution I offered before.
Fit it into your scheme of things.

Anno
 
Reply With Quote
 
Sandman
Guest
Posts: n/a
 
      08-02-2004
In article <cele70$cjh$(E-Mail Removed)-Berlin.DE>,
(E-Mail Removed)-berlin.de (Anno Siegel) wrote:

> Sandman <(E-Mail Removed)> wrote in comp.lang.perl.misc:
>
> [big snip]
>
> > Isn't there a way, while using strict refs, to replace #1#, #2#, #3#...
> > with
> > the values of $1, $2, $3, which are created by a match operation?

>
> Okay, let's treat this in isolation. Suppose you have:
>
> my $string = 'Hello ladies and gentlemen, please step inside';
> my $pattern = 'Hello (.*?) and (.*?),';
> my $template = 'Farewell honorable #2# and fair #1#';
>
> To do the replacements in the most straightforward way, you could
> try this (broken code ahead):
>
> if ( $string =~ /$pattern/ ) {
> $template =~ s/#1#/$1/g;
> $template =~ s/#2#/$2/g;
> }
>
> This doesn't work because we are trying to use $1 and $2 in a
> replacement operation. The pattern match that is the first part of
> the replacement will destroy the contents of $1 and $2, so we can't
> use them that way.
>
> Another problem is that we don't know, in general, how many of $1, $2,...
> will be set by $pattern, so we don't know how many replacement lines to
> write.
>
> To get around both problems, we can use the fact that a match in list
> context returns the captured submatches. So we can loop over them
> without knowing how many there are. This action also de-couples the
> list elements from the actual variables $1, $2, ..., which is slightly
> magical.
>
> We must now generate the marker strings "#1#", "#2#" dynamically.
> So:
>
> my $n = 1;
> for ( $string =~ /$pattern/ ) {
> $template =~ s/#$n#/$_/g;
> $n ++;
> }
>
> Now $template has been transformed into the reply. $string is
> unchanged. This is (in isolation) the same solution I offered before.
> Fit it into your scheme of things.


Thanks - I think I now understand what you are doing there in greater detail,
which I didn't before.

--
Sandman[.net]
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Array of attribute values from object array? danielbigg@googlemail.com Javascript 11 04-13-2009 11:24 AM
Variable displays at one part while does not in another part in a Jack ASP General 8 05-10-2005 07:26 PM
ActiveX apologetic Larry Seltzer... "Sun paid for malicious ActiveX code, and Firefox is bad, bad bad baad. please use ActiveX, it's secure and nice!" (ok, the last part is irony on my part) fernando.cassia@gmail.com Java 0 04-16-2005 10:05 PM
Easy part done, now the hard part!! jollyjimpoppy A+ Certification 0 09-10-2003 10:37 AM



Advertisments