Beefy Boxes and Bandwidth Generously Provided by pair Networks
Clear questions and runnable code
get the best and fastest answer
 
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
Replies are listed 'Best First'.
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 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 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 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 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 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 avoiding work at the Monastery: (4)
As of 2015-08-05 00:58 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    The oldest computer book still on my shelves (or on my digital media) is ...













    Results (76 votes), past polls