Beefy Boxes and Bandwidth Generously Provided by pair Networks Russ
good chemistry is complicated,
and a little bit messy -LW
 
PerlMonks  

regex substitution

by michellem (Friar)
on Nov 05, 2001 at 06:28 UTC ( #123258=perlquestion: print w/ replies, xml ) Need Help??
michellem has asked for the wisdom of the Perl Monks concerning the following question:

Hi folks,

This seems like it should be simple, but I've been struggling with it for a while now. I want to use a regex to substitute a variable declaration in a paragraph with it's value. If I have text like:

my $text = "Your child #child_name# is invited to come to our school. +Your child's teacher will be #teacher_name#, and the class is held in + room #room_number.";

Then I should be able to do something like (I know this is not correct!):
$text =~ s/\#\w+\#/$hash{$&}/g)

Which would result in rows like: Your child Peter is invited...

I know there is a way to do this, but it seems like I have to do two substitutions here - one to substitute #variable_name# to variable_name, then variable_name to $hash{variable_name}. But I can't for the life of me find an example that does this (substitutions within substitutions). Regex's have always kinda stymied me. I did want to solve this with a regex - I'd rather not have to use split, or other methods (which I guess I could). But any example would be helpful.

Thanks for any help!

Comment on regex substitution
Select or Download Code
Re: regex substitution
by rchiav (Deacon) on Nov 05, 2001 at 06:33 UTC
    closer to what you want..
    $text =~ s/#([^#]+)#/$hash{$1}/g
    Rich
Re: regex substitution
by Masem (Monsignor) on Nov 05, 2001 at 06:33 UTC
    Capture a match of the key itself, which you can then use in the replcement part of the regex to get your hash key:
    $text =~ s/\#(\w+)\#/$hash{$1}/g;

    -----------------------------------------------------
    Dr. Michael K. Neylon - mneylon-pm@masemware.com || "You've left the lens cap of your mind on again, Pinky" - The Brain
    "I can see my house from here!"
    It's not what you know, but knowing how to find it if you don't know that's important

Re: regex substitution
by dws (Chancellor) on Nov 05, 2001 at 08:35 UTC
    But I can't for the life of me find an example that does this (substitutions within substitutions).

    When doing substitutions like this, /e is your friend.   $text =~ s/\#\w+\#/$hash{$1}/eg;
    /e forces the right-hand side of the s/// to be evaluated as a Perl expression, and the result substituted for whatever the left-hand side matched. The boundary between interpolation and substitution can seem pretty hazy, but it makes a bit more sense if you imagine that the regexp is "compiled" immediately before it is executed. At that point, $1 either doesn't have a value, or holds a value from a prior regexp. Neither is what you want.

    Consult perlre for full details.

      Perhaps it shouldn't work without /e, but it does, at least with activestate perl 5.6.1. (obviously, you should use strict and warnings...)
      #!perl $_="this is a #fish#\n"; $a{"fish"}="test"; print; s/#(\w+)#/$a{$1}/; print; this is a #fish# this is a test C:\perl -v This is perl, v5.6.1 built for MSWin32-x86-multi-thread (with 1 registered patch, see perl -V for more detail) Copyright 1987-2001, Larry Wall Binary build 626 provided by ActiveState Tool Corp. http://www.ActiveS +tate.com Built 01:31:15 May 2 2001
        Have you read what the /e switch does? I sugguest you do.

        Your argument basically boils down to s/#(\w+)#/$variable/; in which $variable gets expanded, as it will no matter what (if /e is there or not).

        Compare this to:

        #!perl -w use strict; my %hashola = (fish => "test" ); sub f($){ return $hashola{shift @_}; } my $rock = "this is a #fish#\n"; my $block = $rock; print $rock; $block =~ s/#(\w+)#/&f($1);/; # expands $1, doesn't call &f print $block; $block = $rock; # restoree $block =~ s/#(\w+)#/$hashola{$1}/; # expands the variable print $block; $block = $rock; # restoree $block =~ s/#(\w+)#/&f($1)/e; # calls the function print $block; $block = $rock; # restoree $block =~ s/#(\w+)#/$hashola{$1}/e; print $block; $block = $rock; # restoree __END__ F:\dev>perl f this is a #fish# this is a &f(fish); this is a test this is a test this is a test F:\dev>
        Ok ok, from perlop (since s is an operator), I quote:
        e Evaluate the right side as an expression.
        Unless you escape $hashname{$1} like \$hashmane{$1}, the actual variable will be expanded independent of /e, as such is the nature of the s operator.

         
        ___crazyinsomniac_______________________________________
        Disclaimer: Don't blame. It came from inside the void

        perl -e "$q=$_;map({chr unpack qq;H*;,$_}split(q;;,q*H*));print;$q/$q;"

Re: regex substitution
by notsoevil (Pilgrim) on Nov 05, 2001 at 10:42 UTC
    I know "want to solve this with a regex", but I definitely think you may want to look at Text::Template -- there is an example in the documentation that is -very- similiar to what it seems you are trying to accomplish (the apparent goal, not the regex solution necessarily).

    --
    notsoevil
    --
    Jeremiah 49:32 - And their camels shall be a booty. . .

Re: regex substitution
by tomazos (Deacon) on Nov 05, 2001 at 13:08 UTC
    my $text = << 'end_of_test'; Your child <child> is invited to come to our school. Your child's teacher will be <teacher>, and the class is held in <room>."; end_of_test my %hash = ('child' => 'mary', 'teacher' => 'mrs b', 'room' => '123'); print "Raw: $test\n"; $test =~ s[<(\w+)>] [defined($hash{$1}) ? $hash{$1} : warn]ieg; print "Processed: $test\n";
Re: regex substitution
by Dr. Mu (Hermit) on Nov 05, 2001 at 13:18 UTC
    Umm, why not just use variable interpolation?
    foreach (0..@ChildName - 1) { my $text = "Your child $ChildName[$_] is invited to come to our school. Your child's teacher will be $TeacherName[$_], and the class is held in room $RoomNo[$_]."; &PrintNotice($text) # or whatever... }
      Because this isn't within a script - I'm basically allowing users to create their own paragraph-like ouput of database rows. I wanted to have the combination of ease of use for non-savvy users, and ease of me translating the text into the right thing. I might convert to using <> instead of ##. ## is kinda useful because it's the way that some (like Cold Fusion) user-friendly systems use for variables.
Re: regex substitution
by mitd (Curate) on Nov 05, 2001 at 13:28 UTC
    check out a general solution that will also show how to get regex right.

    mitd-Made in the Dark
    'My favourite colour appears to be grey.'

Re: regex substitution
by pike (Monk) on Nov 05, 2001 at 13:47 UTC
    Actually, you were quite close to it, what you could use here is a Hash of Hashes to hold the data:

    my $rhChildren = { {'Peter'} => { child_name => 'Peter', teacher_name => 'Ms. Jones', room_number => '503' } }; #add records as needed my $text = "Your child #child_name# is invited to come to our school. +Your child's teacher will be #teacher_name#, and the class is held in + room #room_number."; foreach my $child (keys %$rhChildren) { my $substText; ($substText = $text) =~ s/\#([^#]+)\#/$rhChildren->{$child}{$1}/g; print "$substText\n"; }

    OK, so there is a redundancy in using the child's name both as key and value in the hash, but it works and uses regexes, right?

Re: regex substitution
by PetaMem (Priest) on Nov 05, 2001 at 14:16 UTC
    Hi,

    If you are into a heavy duty Text pre-processor, you could use Text::Vpp.
    It allows you even such fancy things like perl code being processed while you are doing your preprocessing which will give you the possibility of doing things like:

    if($gender == 'f') { Dear Mrs. $name, } else { Dear Mr. $name, } we would like to invite you...
    We´re using this module for text-preprocessing of TeX-Files for mass printing of letters to our customers. You cannot get it much more flexible and powerfull than that.

    Bye
     PetaMem

Re: regex substitution
by Anonymous Monk on Nov 05, 2001 at 16:22 UTC
    you can group your expression to use it later in your substitution statement: $text =~ s/\#(\w+)\#/$hash{$1}/g; $1 refer to the first grouped expression in your regexp, so variable_name there.
Re: regex substitution
by Anonymous Monk on Nov 05, 2001 at 22:42 UTC

    The previous examples either ignore greedy matching or attempt to to emulate it. I believe this is what you're looking for:

    $text =~ s/#(\w+?)#/$hash{$1}/g;

    --
    pabs (who's too lazy to create an account)
    pabs@pablotron.org
      That would be a problem if \w included the octothorpe. It doesn't, so it's not a problem.
Re: regex substitution
by bigdan (Initiate) on Nov 06, 2001 at 09:30 UTC
    Why waste time reinventing wheels that have already rolled down this path many a time? Read the the perldocs for Text::Template...it's a far more scalable and robust solution than trying to develop your own template language! -dK

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://123258]
Approved by root
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others imbibing at the Monastery: (5)
As of 2014-04-19 16:44 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    April first is:







    Results (483 votes), past polls