[Raleigh-talk] [Perl help] - Multiple substitutions in a file

Matt Nash mattnashbrowns at gmail.com
Tue Feb 22 18:56:54 PST 2011


Hi John,

You are reading the entire file into an array of lines, then processing that
array using a C-style for loop and interpolating the index var into the
search string... and that is the LEAST crazy thing. :)  It works, of course,
because it turns out that there are infinitely many ways to do it.

For your immediate problem of the search-and-replace, I recommend reading
the  whole file into a single string, newlines and all, then using the /gc
modifiers in the regex.  Maybe put your colorChange stuff into an array that
you loop through, checking the regex for the nth match:

@changes = ($change1, $change2, $change3);

foreach $change (@changes) {
    $wholefile =~
s|08\s00\s00\s1C\s\d\d\s\d\d\s\d\d\s\d\d|08\s00\s00\s1C\s$change|gc;
}

see http://perldoc.perl.org/perlre.html and
http://perldoc.perl.org/perlretut.htm<http://perldoc.perl.org/perlretut.html#Using-regular-expressions-in-Perl>
for
lots of details, but the upshot of the modifiers is: g makes it keep looking
for matches; c tells it to remember where it last matched, and start from
there on the next match.  You don't have to care what n is, because you are
matching your search string exactly as many times as you have changes to
make.

...but this project sounds ripe for refactoring, if I may be so bold.  Could
it be that what you really need is a templating system?

Thanks for bringing some much-needed questions to this list!

Matt

On Tue, Feb 22, 2011 at 8:31 PM, John Ricker <sephtin+pm-talk at gmail.com>wrote:

> Received so much help with the last question (which seems to be functioning
> great, btw.. thanks all)... thought I'd try again.  ;)
>
> Have a script that was recently migrated to Perl from shell/bash, and am
> wondering if there's an easy way in Perl to do the following-
>
> File(s) being modified are hex, and look something like:
> ---x---
> ...
> 08 00 00 00 FF FF FF FF FF FF FF FF 1B 00 00 00 02 01 10 00 28 01 00 00 09
> 00 00 00 FF FF FF FF FF FF FF FF 1C 00 00 00 14 00 14 00 0D 00 00 00 00 00
> 0D 00 18 00 00 00 11 00 00 00 FF FF FF FF 08 00 00 05 02 0E 00 00 18 00 00
> 00 0E 00 00 00 FF FF FF FF 08 00 00 1C 00 00 00 FF 18 00 00 00 09 00 00 00
> FF FF FF FF 08 00 00 11 10 00 00 00 18 00 00 00 0F 00 00 00 FF FF FF FF 08
> 00 00 01 11 02 02 01 18 00 00 00 03 00 00 00 FF FF FF FF 08 00 00 01 05 00
> 08 01 18 00 00 00 10 00 00 00 FF FF FF FF 08 00 00 05 01 0F 00 00 18 00 00
> 00 05 00 00 00 FF FF FF FF 08 00 00 05 01 0F 00 00 18 00 00
> ...
> ---x---
> File(s) contain several occurrences of "08 00 00 1c ## ## ## ##" or more
> appropriately for this list: "08\s00\s00\s1C\s\d\d\s\d\d\s\d\d\s\d\d"
>
> Now on to the good stuff...  I would like to replace the ## ## ## ## with
> my chosen colors, that are being provided by vars... Example:
> colorChange1="FF 00 00 FF"
> colorChange2="FF FF 00 FF"
> colorChange3="FF 00 FF FF"
> ...
>
> I'm wondering how it might be possible, to replace the FIRST occurrence (in
> the file, NOT in a line) of "08 00 00 1C ## ## ## ##" with "08 00 00 1C
> $colorChange1", the second with "08 00 00 1C $colorChange2", etc.
>
> More info:
> --Script modifies files to theme them, in this case, I'm taking a BINARY
> (compiled XML) file, converting it to HEX via xxd, and then changing the
> text color for a theme via substitution.
> --I originally thought it could be done similar to what sed does... with
> s|(08\s00\s00\s1C)\s\d\d\s\d\d\s\d\d\s\d\d|$1$colorChange1|1  (note last
> digit...), but testing has shown that this doesn't work as expected.
> --Not really related, but in the binary, the colors are actually backwards,
> so color - FF AB CD EF becomes binary - EF CD AB FF, but that's an easy
> change.
> --CURRENTLY in my script, I'm doing this via a sub, passing an array of the
> colors, the file, and the file location (directory), and pulling the file,
> making the changes, and saving it back out via loop... BUT, because I
> couldn't figure out how to just do the multiple replaces... I cheated and
> made template files that contain "08 00 00 1C 11 11 11 11" and "08 00 00 1C
> 22 22 22 22", so when I iterate through the loop, I just change like so:
> for ( $i = 1 ; $i <= $COUNT ; $i++ ) {
> ...
>     $line =~ s|08\s00\s00\s1c\s$i$i\s$i$i\s$i$i\s$i$i\s|08 00 00 1c
> $array_ref[$i]|;
> ...
> }
>
> Code works, but I'd much rather be able to pull native files straight out
> of the .zip, and change them that way... :P
>
> Anyway, again, if there are specifics I missed, happy to provide them.
> I keep thinking there should be an easy way to do this... but my google-fu
> is failing me..
>
> Thanks again for the help with the previous problem, and in advance for any
> assistance on this one.  :)
> At the very least, I guess I can provide some chatter to the group.
>
> -John (sephtin @gmail)
>
> _______________________________________________
> Raleigh-talk mailing list
> Raleigh-talk at pm.org
> http://mail.pm.org/mailman/listinfo/raleigh-talk
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.pm.org/pipermail/raleigh-talk/attachments/20110222/a995fcb4/attachment.html>


More information about the Raleigh-talk mailing list