简体   繁体   中英

Regex - matching a multiline block by noting the absence of a string and then inserting it

What a mouthful of a subject.

So in essence I have a pattern I need to find in a file based on that pattern missing something.

For example what I HAVE is:

Huge amounts of preceding code...

someHeader
                {
                        someInfo = "blah blah blah";
                }

Huge amounts of ending code...

What I need to do is make it look like this:

someHeader
                {
                        someDescription = "Excellent information found here!";
                        someInfo = "blah blah blah";
                }

Huge amounts of ending code...

The bottom line: I need to find all instances of the "someHeader" block that do not have a "someDescription" and insert it. "someInfo" will not always be there either so I really need to find every instance of "someheader\\r\\t\\t{\\r\\t\\t\\t!someDescription" and replace it with "someheader\\r\\t\\t{\\r\\t\\t\\tsomeDescription = "Excellent information found here!";\\r"

I really am at a loss and have been banging on this for about a day. I have attempted , , and am dorking around with right now.

Consider the algorithm:

  1. Reading the file line by line
  2. If the line matches "someHeader":

    1. Create a new buffer, but the current line into it

    2. Keep reading more lines into the buffer until the line matches a "}"

    3. If the buffer doesn't contain "someDescription", then insert it

    4. Print the buffer

  3. Otherwise print the line

Here's a basic Perl implementation:

#!/usr/bin/perl -n

if (/^someHeader/) {
    $buf = $_;
    while (($line = <>) !~ /}/) {
        $buf .= $line;
    }
    $buf .= $line;
    if ($buf !~ /someDescr/) {
        $buf =~ s/{/{\n    someDescription = "Excellent";/;
    }
    print $buf;
} else {
    print;
}

Use it as:

perl parser.pl < sample.cc

This code won't win beauty contests but it should work. You'll probably need to make the regular expressions more strict to avoid false positives, and of course you'll need additional code to actually update your source files. Good luck.

I like Joe Z 's parser suggestion, but perhaps the following--which uses a negative look-ahead--may provide some assistance:

use strict;
use warnings;

my $string = do { local $/; <DATA> };
my $replacement = qq{someDescription = "Excellent information found here!";\n\t\t\t};

$string =~ s/(?:someHeader\n\t\t{\n\t\t\t)\K(?!someDescription)/$replacement/gs;
print $string;

__DATA__
someHeader
        {
            someDescription = "Excellent information found here!";
            someInfo1 = "blah blah blah";
}

someHeader
        {
            someInfo2 = "blah blah blah";
}

Output:

someHeader
        {
            someDescription = "Excellent information found here!";
            someInfo1 = "blah blah blah";
}

someHeader
        {
            someDescription = "Excellent information found here!";
            someInfo2 = "blah blah blah";
}

This might work for you (GNU sed):

sed '/someHeader/{:a;$!N;/}/!ba;/someDescriptiom/!s/\(\n\s\+\){/&\1\tsomeDescription = "Excellent information found here!";/}' file

On encountering someHeader read more lines until a } is found. Search the result for someDescription and if not found append someDescription bla bla ... following the first { .

NB Nested braces and all bets are off!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM