Beefy Boxes and Bandwidth Generously Provided by pair Networks
P is for Practical
 
PerlMonks  

string replacement

by colox (Novice)
on Sep 12, 2017 at 15:07 UTC ( #1199207=perlquestion: print w/replies, xml ) Need Help??
colox has asked for the wisdom of the Perl Monks concerning the following question:

hi perlmonks, would like to seek your expertise on how to code this:

if i have a config/look-up file containing like below:

AAA = AAA123 BBB = XYZ999 DEF = ANYOTHER

then i have multiple files where I would like to replace the string containing the string patterns from the left side above & replace with the string on the right. my objective is to keep the base code & just update the look-up file of the string pattern to search & the corresponding string to replace in the files.

I look forward to your valuable inputs.

Replies are listed 'Best First'.
Re: string replacement
by Eily (Parson) on Sep 12, 2017 at 15:41 UTC

    Please edit your post to correct the formatting. See Markup in the Monastery. You should at least use <code> tags around your config file so that it can be displayed properly.

    The "search and replace from a list of replacements" part can be done using a hash, and the substitution operator.

    use strict; use warnings; my $text = "I will not stir from this place, do what they can."; my %replacements = ( "will not" => "won't", "stir" => "move", "this place" => "here", "do what they can" => "let them try"); my $pattern = join "|", map quotemeta, keys %replacements; print "The pattern is: $pattern\n"; my $replaced = $text =~ s/($pattern)/$replacements{$1}/gr; print $replaced;
    The pattern part is a regular expression if you don't know about them you can look at those tutorials.
    The quotemeta escapes the special characters in the search items so that they are interpreted litteraly in the regular expression.
    The s/search/replace/ part is what does the actual job, the search part will capture the strings it finds (because of the parenthesis) into $1, and $replacements{$1} will return the matching replacement. The g in /gr means "general", and will apply the change everywhere in the string, not just once, and the r means "return", so the result is returned to $replaced, instead of changing $text itself.

    As for reading your config file, one of the config modules might do what you want.

      my $pattern = join "|", map quotemeta, keys %replacements;

      I think it would be good to also sort on length, as I discussed in Building Regex Alternations Dynamically. Although huck does make a good point that preserving the original ordering may be important too. Update after your reply: Good point about replacements within the replacements, whether the OP wants that or not and which method is more appropriate will depend on their requirements.

        You're right about putting the longest strings first, if one searched string can be the start of another. That would be my $pattern = join "|", map quotemeta, sort {length $b <=> length $a} keys %replacements;.

        With a single substitution operator you don't have to look for the presence of a searched string inside a replacement, because perl will only keep searching after the replaced item, so you can't replace part of a replacement.

      thanks you so much for the inputs!...
Re: string replacement
by huck (Vicar) on Sep 12, 2017 at 15:31 UTC

    This problem is not quite as simple as it seems. There are a number of cpan ways to read a parm file. Lets bypass that for now and focus on the replacement. The replace pairs are already in hashs that are part of an ORDERED array here.

    use strict; use warnings; my @reps; push @reps,{from=>'ZZZ',to=>'456AAA456'}; push @reps,{from=>'AAA',to=>'AAA123'}; push @reps,{from=>'BBB',to=>'XYZ999'}; push @reps,{from=>'DEF',to=>'ANYOTHER'}; while (my $line=<DATA>) { chomp $line; for my $rep (@reps){ my $from=$rep->{from}; my $to =$rep->{to}; $line=~s/\Q$from\E/$to/g; } # rep print $line."\n"; } # line __DATA__ AAAA more stuff stuff BBB again DEF stuff |ZZZZ| not as simple as it seems
    Result
    AAA123A more stuff stuff XYZ999 again ANYOTHER stuff |456AAA123456Z| not as simple as it seems
    As you can see, if a "to" contains a "from" the order of execution is important. There is a lot that could be improved here, pre-compiling the regexp parts for instance, but this is a simple demo of how it can be done and one of the pitfalls.

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1199207]
Approved by Eily
help
Chatterbox?
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others wandering the Monastery: (3)
As of 2017-10-20 09:42 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    My fridge is mostly full of:

















    Results (260 votes). Check out past polls.

    Notices?