search/replace values from an array - Part 2.

Discussion in 'Perl Misc' started by Sandman, Aug 2, 2004.

  1. Sandman

    Sandman Guest

    Hello again, and thanks to Anno Siegel for your answer to my earlier thread
    (news:) 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]
    Sandman, Aug 2, 2004
    #1
    1. Advertising

  2. Sandman

    Anno Siegel Guest

    Sandman <> wrote in comp.lang.perl.misc:
    > Hello again, and thanks to Anno Siegel for your answer to my earlier thread
    > (news:) 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
    Anno Siegel, Aug 2, 2004
    #2
    1. Advertising

  3. 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
    Gunnar Hjalmarsson, Aug 2, 2004
    #3
  4. Sandman

    Sandman Guest

    In article <cel5b7$66f$-Berlin.DE>,
    -berlin.de (Anno Siegel) wrote:

    > > Hello again, and thanks to Anno Siegel for your answer to my earlier thread
    > > (news:) 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]
    Sandman, Aug 2, 2004
    #4
  5. Sandman

    Sandman Guest

    In article <>,
    Gunnar Hjalmarsson <> 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]
    Sandman, Aug 2, 2004
    #5
  6. Sandman

    Anno Siegel Guest

    Sandman <> 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
    Anno Siegel, Aug 2, 2004
    #6
  7. Sandman

    Sandman Guest

    In article <cele70$cjh$-Berlin.DE>,
    -berlin.de (Anno Siegel) wrote:

    > Sandman <> 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]
    Sandman, Aug 2, 2004
    #7
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. cindy
    Replies:
    0
    Views:
    490
    cindy
    Aug 14, 2009
  2. Abby Lee
    Replies:
    5
    Views:
    378
    Abby Lee
    Aug 2, 2004
  3. Sandman

    search/replace values from an array...

    Sandman, Aug 1, 2004, in forum: Perl Misc
    Replies:
    5
    Views:
    116
    Eric Bohlman
    Aug 3, 2004
  4. ebm

    search and replace on an array

    ebm, Jun 30, 2006, in forum: Perl Misc
    Replies:
    8
    Views:
    94
    Uri Guttman
    Jun 30, 2006
  5. Jimmy
    Replies:
    13
    Views:
    427
    Arne Vajhøj
    Jul 25, 2012
Loading...

Share This Page