Norman Zhang
Norman Zhang

Reputation: 21

Regex to Match String in Multi-Line String

I have some string in a text file.

line con 0
 session-timeout 10 
 exec-timeout 10 0
 privilege level 15
 logging synchronous
 login authentication console-in
 transport preferred none
 stopbits 1
line vty 0 4
 session-timeout 30 
 exec-timeout 30 0
 logging synchronous
 transport preferred none
 transport input ssh
 transport output ssh
line vty 5 15
 session-timeout 10 
 exec-timeout 10 0
 logging synchronous
 transport preferred none
 transport input ssh
 transport output ssh

I'm trying find/match

session-timeout 10
exec-timeout 10

only under the line con 0 with Regex.

line con 0.*\n(.*\n)*.*session-timeout 10.*\n(.*\n)*.*exec-timeout 10 will also catch

vty 5 15
 session-timeout 10
 exec-timeout 10

Is there a way to do better?

Upvotes: 1

Views: 103

Answers (2)

The fourth bird
The fourth bird

Reputation: 163207

If the 2 lines session-timeout 10 and exec-timeout 10 should occur in that order, you can use 2 capture groups.

Per capture group value, make sure that the lines that precede it do not cross matching either line and for example session- for the first match and exec- for the second match using a negative lookahead.

^line con 0(?:\r?\n(?!line | session-).*)*\r?\n[\p{Zs}\t]*(session-timeout 10).*(?:\r?\n(?!line| exec-).*)*\r?\n[\p{Zs}\t]*(exec-timeout 10)\b
  • ^ Start of string
  • line con 0 Match literally
  • (?:\r?\n(?!line | session-).*)* Match all lines that do not start with line or session-
  • \r?\n[\p{Zs}\t]* Match a newline and optional spaces or tabs
  • (session-timeout 10) Capture group 1, match literally (or use [0-9]+ to match 1+ digits)
  • .* Match the rest of the line
  • (?:\r?\n(?!line| exec-).*)* Match all lines that do not start with line or exec-
  • \r?\n[\p{Zs}\t]* Match a newline and optional spaces or tabs
  • (exec-timeout 10) Capture group 2, match literally
  • \b A word boundary to prevent a partial match

See a regex 101 demo and a .NET regex demo(Click on the "Table" tab to see the groups)

Upvotes: 1

Gwang-Jin Kim
Gwang-Jin Kim

Reputation: 9865

It is because greedy behavior which is the default behavior of regex matching (it tries to expand the match as much as possible while matching the pattern). Adding ? after quantifiers + or * solves the problem of greediness.

Therefore use the pattern:

line con 0.*?\n(.*?\n)*?.*?session-timeout 10.*?\n(.*?\n)*?.*?exec-timeout 10

Which tries to match as few lines as possible.

It matches

line con 0
 session-timeout 10 
 exec-timeout 10

Upvotes: 0

Related Questions