0

I have a config file:

config line 1
....
config line n
router mk1
 ip 10.1.1.2
 deviceType t1
 sub config line!
 sub config line 2
 !more sub config
!
 !!!
more config lines
router mk2
 ip 10.1.1.2
 sub config line1
 sub config line 2
 deviceType t2
!

Each router block starts with the word router on a new line and ends with ! on a new line. A config file can contain many router blocks.Each sub-block begins with a single space.The lines in sub-block can be in any order.I want to select a block that contains a specific line for eg: deviceType t2.

So far I could identify all the router blocks with the following:

(?ms)^router mk.*?^!$

But I only need a block that contains the line deviceType t2

0

3 Answers 3

1

The following regular expression should work for most all regex engines (though it may be necessary to replace \R with \r?\n). I tested it with the PCRE (PHP) regex engine.

(?m)^router .+\R(?: .*\R)* deviceType t2\R(?: .*\R)*!$

Start your engine!

The engine performs the following operations.

(?m)            : multiline mode (^ and $ match beginning and end of line)
^               : match start of line
router .*\R     : match line beginning 'router ', including terminator
(?: .*\R)*      : match a line including terminator that begins with a
                  space in a non-capture group, execute 0+ times
deviceType t2\R : match line 'deviceType t2', including terminator
(?: .*\R)*      : match a line including terminator that begins with a
                  space in a non-capture group, execute 0+ times
!$              : match the line '!'
Sign up to request clarification or add additional context in comments.

3 Comments

You could also accomodate empty lines by changing all \R in my regex to \R+.
@pradeepk6 I am afraid your small change spoilt the expression, see regex101.com/r/0hM5aC/3.
@Ryszard Czech can you help with this? stackoverflow.com/questions/62386844/…
1

You may use

(?m)^router mk\d+(?:\R(?!router mk\d+$).*)*?\R\s*deviceType t2(?:\R.*)*?\R!$
(?m)^router mk\d+(?:\n(?!router mk\d+$).*)*?\n\s*deviceType t2(?:\n.*)*?\n!$
(?m)^router mk\d+(?:\r?\n(?!router mk\d+$).*)*?\r?\n\s*deviceType t2(?:\r?\n.*)*?\r?\n!$

See the regex demo. The variations are for different kinds of line break sequences, \R matches any line break, \n only matches LF line endings, and \r?\n matches CRLF or LF line endings.

Details

  • (?m) - MULTILINE mode on
  • ^ - line start
  • router mk\d+ - router mk and 1+ digits
  • (?:\R(?!router mk\d+$).*)*? - 0 or more occurrences, but as few as possible, of the following sequence of patterns:
    • \R(?!router mk\d+$) - a line break sequence not followed with router mk + one or more digits at the end of a line
    • .* - any 0 or more chars other than line break chars, as many as possible
  • \R\s* - a line break sequence and then 0+ whitespaces
  • deviceType t2 - a literal string
  • (?:\R.*)*?
  • \R - line break sequence
  • ! - !
  • $ - end of line.

5 Comments

Thanks very much @wiktor Stribizew.I did not find this topic in any of the books.So your help is much appreciated. Ru sure there is no easier or elegant regex??What if the selection criteria is I want a block that contains 2 sub-config lines instead of just one sub-config line.Mind you the sub-conifg lines can be in any order.Flavour is Java
@pradeepk6 Do not use regex in such cases. Especially in Java. Extract all blocks using any kind of regex you find "elegant" (I prefer efficient to "elegant", something like (?m)^router mk\d+(?:\R.*)*?\R!$), and then check if the expected substrings are present inside the matches.
@pradeepk6 My solution is not complex. It follows the requirements you described in the question. Cary's solution relies on your string sample: he assumes the lines in a block all start with a literal space. I just use a lookahead to check if we hit the line that is equal to !. The regexps are basically the same. Cary does not check if router name follows mk+digits pattern though. Simplest != the most precise != the most efficient. Also, there is no mentioning in your question that you seek the simplest pattern. You would have to explain what you mean by "simple".
Stribizew Thanks once again for all your help.
The OP did not say that ”router" began the line that contained it, or that it was followed by a space, but we all assumed that was the case, based on the example. Beyond that, my understanding of the question was guided only by the content of the paragraph, "Each router block starts...", which is quite precise.
1

don't wurry boute line endings, most engines have multi-line mode

try (?m)^router.*\s*(?:^(?!!).*\s*)*?^\s*deviceType\s+t2.*\s*(?:^.*\s*)*?^!

uses fewest steps, yes ?

demo

2 Comments

too clever Sir.
The downvoter is back. I seem to get one on every regex answer I post. I’ve noticed that you seem to be collecting them as well. At my main haunt at SO I only get them on nights when there’s a blue moon.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.