in reply to Re^2: adding lines at specific addresses
in thread adding lines at specific addresses

I think your three-step plan is making things more complicated than they need to be. For one thing, the list of labels that you need (assuming that you really do need these) should be stored in a hash. Just figure out what piece of information about each label will make sense in your app as a hash key (i.e. the thing you'd want to use later for looking things up), and what information will be useful (if anything) as a hash value.

Use more than one hash if that makes things easier (but often, a single hash will do).

As for working out how to construct the output file, it would be better, if possible, for the changes to be made and output produced as you're reading the input. For example, if you somehow know that you need to insert a "(LIG O 51 ...)" line and you input a line that has "(LABEL O 52)", do you have enough information at this point to output the line(s) that should precede "(LABEL O 52)" ?

If you need to read the whole input before resolving that sort of problem, that's okay -- but again, it may be better to hold the input data in a suitable structure (AoH or HoA or somesuch) to reduce the risk of scrambling it beyond recognition.

You showed us an "easy" example in the OP, but you haven't given us a clear example of a "hard" case -- what it looks like on input, and what you'd like it to look like on output -- maybe I'm missing something, but this part isn't clear to me based on what you've said so far.

  • Comment on Re^3: adding lines at specific addresses

Replies are listed 'Best First'.
Re^4: adding lines at specific addresses
by pindar (Initiate) on Oct 11, 2005 at 10:47 UTC
    Yes, I think you're tight about making things harder than necessary... I came up with this solution. It makes for ugly spaghetti code, I guess, but it seems to work(TM). First, I need to slurp in the entire file since I want to match across newlines:
    my @lines = (<>); my $text = join "", @lines;
    Then, I test for each LABEL from LABEL O 0 to LABEL O 255. If the label exists, write it to another file, adding the new instructions. If it doesn't exist, just write the new instructions:
    if ($text =~ m/( \(LABEL O 1\))(\n.+?)( \(STOP\)\n)/s) { $labelo1 = $1; $labelo1instructions = $2; print "$labelo1\n NEWLIGINSTRUCTIONS HERE$labelo1instructions"; } else { print "(LABEL O 1)\n NEWLIGINSTRUCTIONS HERE\n"; }
    I tried Tie::File, but couldn't get my head around it. And everything I tried with it was incredibly slow, so I went back to the brute-force approach... Thanks for all your help!!
      Well, on the whole, that's not so bad... But if you are creating 256 copies of that "if ... else ..." block, one for each possible numeric following "LABEL O", then you really have missed some important points about programming in general (understanding loops and variables) and about perl in particular (using regular expressions).

      For that matter, I think the regular expression you've shown is probably not what you really want -- try putting square brackets around the "\n." -- and don't forget to include $3 when you print stuff out.

      You also want to meet a new friend: $/ also known as "$INPUT_RECORD_SEPARATOR" (look for a description of it here: perlvar -- it's about a quarter of the way down). Based on this new information you've shown, it looks like the input data is structured in blocks, where each block ends with "(STOP)\n". You can tell perl to use that string and the end-of-record marker, instead of the default "\n", and simplify your code immensely:

      open( IN, "some_file.tex" ) or die $!; { local $/ = "(STOP)\n"; my $expected_id = 1; while (<IN>) { # read a whole block up to "(STOP)\n" if ( s/\(LABEL O $expected_id\)\n/$1 NEWSTUFF/ ) { print; # all done with this block } else { print "(LABEL O $expected_id)\n NEWSTUFF\n(STOP)\n"; # add a new block } my $expected_id++; } } # closing this block drops the local value of $/ # now $/ is back to it's default value (in case you # have to read other stuff in the normal fashion).
      So, does it really need to be any more complicated than that?
        "you really have missed some important points about programming in general (understanding loops and variables) and about perl in particular (using regular expressions)."

        I couldn't agree more, I'm just a humanities guy dabbling in perl scripting... Your code looks wonderful, and in fact, I had been thinking about something to that effect, but there are two problems that make such a loop impracticable:

        1. Some of the values are not given as LABEL O (number), but as LABEL C A or LABEL C a, so I'd need more than one loop.

        2. (probably trivial, but insurmountable to me) The numbers O XXX are octal numbers, and I couldn't figure out how to make perl increment the $i++ in octals.

        Again, thanks for your help!