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

Hello all and Happy New Year!! I only dabble in perl, just enough to be dangerous so hopefully this one isn't out of bounds. I have a bunch of files I need to modify, within each file are multiple sections, here's an example of part of a file.

C 1298 1 28 0
A 1920 1035 10 0 9 3 #=12
I 1284 vtg:CAP 2 2250 1045 0 1 '
A 2285 1035 10 0 3 0 PKG_TYPE=SMC0805
A 2285 1065 10 0 3 3 REFDES=C25
A 2285 1055 10 0 3 3 VALUE=334P
A 2285 1045 10 0 3 3 VOLTAGE=16V
A 2285 1025 10 0 3 1 TOL=20%
C 1309 5 3 0
A 2270 1075 10 0 3 3 #=1
C 1296 3 4 0
A 2270 1045 10 0 3 3 #=2
I 1283 vtg:DRAM 2 2250 985 0 1 '
A 2285 1005 10 0 3 3 REFDES=U23
A 2285 975 10 0 3 0 PKG_TYPE=TQFP144
C 1310 3 4 0
A 2270 985 10 0 3 3 #=2

I need to change the value of PKG_TYPE according to an array I have that lists the new PKG_TYPE values by their REFDES value. Each section I need begins with I and is followed by one or more A lines in no particular order. Not sure where to go with this one. Maybe identify an I-beginning line then put each following A-beginning line into a hash until I hit another character? I've never used hashes before either, be gentle.

Any assistance or direction would be greatly appreciated. Thanx.

Replies are listed 'Best First'.
Re: Modify a line following a target line?
by ikegami (Patriarch) on Jan 05, 2009 at 21:31 UTC
    If you can load the entire file into memory, the following will split the file into records:
    my @records = split(/^(?=I)/m, $file);

    The just extract the REFDES and modify the PKG_TYPE

    my %pkg_lkup ( ... => ..., ... => ..., ... => ..., ); for my $rec (@records) { if ( my ($refdes) = $rec =~ /REFDES=(.*)/ ) { if (exists($pkg_lkup{$refdes})) { $rec =~ s/PKG_TYPE=.*/PKG_TYPE=$pkg_lkup{$refdes}/; } } print($rec); }

    In Perl 5.10, the substitution can be written more efficiently as

    $rec =~ s/PKG_TYPE=\K.*/$pkg_lkup{$refdes}/;
      OK I think I understand this all for the most part, I've been working on files on a line by line basis for so long I didn't think I could break it up any other way. But of course something I imagine is pretty simple has got me stuck.

      How do I get the entire content of a file into $file? I know how to read a file into @file, but I'm at a loss how to read the whole thing into $file to then split it up.

        The canonical solution is:

        my $file = do { local $/; <>; };

        But, we're in Perl, so there's more than one way to do it.

        $file = join( '', <> );

        also works. Of course, you could look at File::Slurp for a CPAN-based solution that's a little more readable.

        PS. if you have an open filehandle in $fh, you would replace <> with <$fh> in the above, of course.

        G. Wade
Re: Modify a line following a target line?
by ccn (Vicar) on Jan 05, 2009 at 21:38 UTC
    #!/usr/bin/perl -- use strict; use warnings; die "Usage: $0 filetoprocess\n" unless @ARGV; my %subst = ('C25' => 'SMS0011', 'U23' => 'TQF0022', # ... 'U25' => 'TQF1223', ); $/ = "\nI "; # use own input record separator while (<>) { # read a record and substitute if a ma +tch found if (my ($rd) = /REFDES=(\w+)/) { s/PKG_TYPE=(\w+)/PKG_TYPE=$subst{$rd}/ if exists $subst{$rd}; } print; }