JojoLinkyBob has asked for the wisdom of the Perl Monks concerning the following question:

I want to read in a text file, and make a search n replace with each item that matches the pattern, and is also a member of the hash I'm checking. The way I'm doing it here can be dangerous because I can't guarantee that it'll match the particular expression each time (or worse, it may go into infinite regression (e.g. replace a with ab)), so what I was thinking about doing was storing it into a list (tokening by whitespace probably) and this would give me the ability to manipulate each token separately.

But if I do such a thing, how can I re-create the original file, since I don't have easy access to the delimiters once the list is created.

Note: The delimiting characters may include more than just whitespace. Thanx!
open (fp,$ARGV[0]) || die ("Can't open $ARGV[0]! Exiting."); while (<fp>) { if (!m/^\s*\/\//) #Ignore commented lines { s/\/\/.*//g; while (m/([A-Za-z0-9_\.\:]+)/g) { if (exists $my_replacement{$1}) { s/$1/$my_replacement{$1}/; } } } print $_; }
Desert coder

Replies are listed 'Best First'.
Re: Read In A File, Manipulate It, Spit It Back Out
by dsb (Chaplain) on Jul 07, 2001 at 01:09 UTC
    I tried essentially what the same code that you posted, and in looking at it, I saw that you are trying to use $1 in the substitution regex. As far as I can see, using a regex resets the $n($1,$2,etc.) variables all to undefined regardless of whether they are reused or not. Try assigning your $1 variable to a $tmp variable or something like this:
    while (<FH>) { while ( $_ =~ m/(?:\s|\W)*([A-Za-z0-9_\.\:]+)(?:\s|\W)*/g ) { if ( exists $hash{$1} ) { $tmp = $1; $_ =~ s/$tmp/$hash{$tmp}/; } } $data .= $_; }
    Hope that helps.

    *NOTE: I'd normally be using 'strict' btw. ;)

    Amel - f.k.a. - kel

      using a regex resets the $n($1,$2,etc.) variables all to undefined regardless...

      As it happens, this is not always the case. It is true that if the second regex succeeds, unused numbered variables from a previous regex do become undefined -- even if the new regex contains no capturing paren's.

      But in the case given in the question, the $1 will not be undefined until after the second regex is evaluated. So the $1 in the second regex will reflect the value from the first regex if it succeeded. Example:

      my $str = "a2b c34d"; $str =~ /(\D\d\D)/; print "$1\n"; # prints: 'a2b' $str =~ s/$1/NEW/; print "$str\n"; # prints: 'NEW c34d'

      As different hazzard, (distinct from the example in the stated question) if the second regex fails, the previous values are retained (not undefined). This can cause intermittent problems that can be hard to trace. Consider:

      my $str = "a2b c34d"; $str =~ /(\D\d\D)/; print "$1\n"; # prints 'a2b' $str =~ /(xyz)/; print "$1\n"; # prints 'a2b' again
      Thanx, I'll have to remember that. Desert coder
Re: Read In A File, Manipulate It, Spit It Back Out
by I0 (Priest) on Jul 07, 2001 at 10:35 UTC
    s/([A-Za-z0-9_\.\:]+)/$my_replacement{$1}||$1/eg
      Succintly beautiful, thanks! :) Desert coder
Re: Read In A File, Manipulate It, Spit It Back Out
by MZSanford (Curate) on Jul 07, 2001 at 13:27 UTC
    I think that /g could prevent the recursion problem, so i have two way that would work :
    # version 1 ## problem, does not skip comments undef($/); my $text = <fp>; foreach my $pat (keys %my_replacement) { $text =~ s/$pay/$my_replacement{$pat}/g; } print $text;
    ... and ...
    while (<fp>) { if (!m/^\s*\/\//) { # skip comments next; } $text .= $_; } foreach my $pat (keys %my_replacement) { $text =~ s/$pay/$my_replacement{$pat}/g; } print $text;

    may the foo be with you