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

Hi Everyone,

Just so we are all clear... I am completely lost right from the start with this one. It is far beyond my current Perl skills and I need some serious help :)

I want to create a script that searches file_b for the first entry in file_a (router1 in the below example) and once it finds it I would like it to change the next occurrence of "Parent Submap: Any string" to "Parent Submap: second entry in file_a (site1 in the below example)"

It would also need to be case-insensitive.

Can anyone give me a huge push in the right direction?

Thank you.

-Chris

-------------------------------------
External files:
file_a - list of routers and their location
Eg:
router1,site1

file_b - output from an openview map export, contains 1000¡¦s of entries like the below example.
Eg:
SYMBOL: ROUTER1
Object Type: 4
Parent Submap: IP Internet
Symbol Type: Cisco Router:cisco-Rtr1720Family
Label: ROUTER1
Symbol Position: 1:11764x11691+7126+653
Hidden Value: FALSE
Submap Exists: TRUE
Background Graphics:
Layout Style: 2
Layout On: TRUE
Submap Overlay: TRUE
Show Connection Labels: FALSE
END SYMBOL

Replies are listed 'Best First'.
Re: Searching and replacing text
by graff (Chancellor) on Jul 29, 2004 at 05:51 UTC
    Since you asked for a push, here's some pseudo-code, which you should be able to translate into perl:
    read first line from file_a split the line into scalar variables ("machine" and "site") open file_b while reading a line at a time from file_b { if the line contains "machine", set $apply_edit to true elsif the line contains "Parent Submap: " and $apply_edit is true +{ replace the rest of this line with "site" reset $apply_edit to false } print the line }
    I expect others will propose more elegant and compact methods, but this is, I think, easy to comprehend. Note that watching for the "machine" name involves a regex match with the "i" modifier at the end, to ignore case. When expressed in perl, this approach can involve less typing than the pseudo-code I gave you.
      But you can't just substitute arbitrary text in a text file, unless it happens to have exactly the same length. As file_b is being read and searched, each line should be copied out to a new file, and updated line printed in it's proper order, and the remainder of file_b copied. Then rename the new file to file_b (making sure file_b is closed).
        Yes, I glossed over the output management part, thinking the OP probably had a handle on that already (unfortunate pun duly noted).

        As often as not for things like this, I just make the script print to STDOUT and put the file handling stuff on the command line -- why right write more lines of perl code to do stuff that the shell can do for me with an angle bracket?

        text-altering-script.perl input.file > output.file # optional step: mv output.file input.file
Re: Searching and replacing text
by Skeeve (Parson) on Jul 29, 2004 at 10:37 UTC
    WARNING: Untested, incomplete code ahead

    I would create this script in form of a filter:
    #!/usr/bin/perl -i.bak :
    and would make the file_a an option so that you can do it like this:
    $ ./myfilter -i file_a file_b
    This would then create a new file_b and preserve a backup file_b.bak.

    First thing you should do in the filter is find all the things you'd like to replace in file_b (should it be more than just one) and store it in a hash:
    while (<filea>) { if ( this is a line i want ) { s/[\015\012]+$//; # Just to remove any CR/LF my($router,$site)= split /,/,$_,3; $replace{$router}= $site; } } my $replacements= '\b('.join('|',keys %router).')\b';
    After that you have a list of texts to search for as keys %replace and the replacement as $replace{...}. You also have a string of the form: \b(router1|router2...|routerN)\b that will be used in a regular expression.

    When you've done with that, simply read and write what ever comes through <> replacing what you need:
    my $symbol; while (<>) { if (my $hit/^SYMBOL: $replacements/i ... /^END SYMBOL/i) { if ($hit==1) { $symbol=$1; } else { s/^(Parent Submap:).*/$1 $replace{$symbol}/; } } print; }
    That's it.