Python regex how to find a substring that starts with a given word and ends with either of two words

Viewed 101

I'm parsing a log file and trying to find a substring that starts with a given pattern (say Start log ) and ends with one of two patterns (say exit code \d. or took \d* seconds.), whichever is later.

I tried the following without success:

block_regex1 = re.compile('Start log .*?(exit code \d.|took \d* seconds.)', re.DOTALL)
block_regex2 = re.compile('Start log .*? exit code \d.|Start log .*? took \d* seconds.)', re.DOTALL)

block_regex.findall(log)

Example log file:

Start log 1
doing stuff
Finished with exit code 1.
Start log 2
doing stuff
Finished with exit code 0.
log 2 took 12 seconds.
Start log 3
doing stuff
Finished with exit code 0.
log 3 took 10 seconds.
Start log 4
doing stuff
Finished with exit code 1.

With the above code it should output a list with:

  • Start log 1 doing stuff Finished with exit code 1.
  • Start log 2 doing stuff Finished with exit code 0. log 2 took 12 seconds.
  • ...

Eventually I want to get the log ID, the exit code, and if present the time in seconds. I think I can get that using groups, still looking into it.

1 Answers

Use

Start log (?:(?!Start log).)*(?:exit code \d+|took \d* seconds)\.

See proof. In short: matching as much text as possible from Start log until exit code or took xxx second without allowing Start log in between.

EXPLANATION

--------------------------------------------------------------------------------
  Start log                'Start log '
--------------------------------------------------------------------------------
  (?:                      group, but do not capture (0 or more times
                           (matching the most amount possible)):
--------------------------------------------------------------------------------
    (?!                      look ahead to see if there is not:
--------------------------------------------------------------------------------
      Start log                'Start log'
--------------------------------------------------------------------------------
    )                        end of look-ahead
--------------------------------------------------------------------------------
    .                        any character except \n
--------------------------------------------------------------------------------
  )*                       end of grouping
--------------------------------------------------------------------------------
  (?:                      group, but do not capture:
--------------------------------------------------------------------------------
    exit code                'exit code '
--------------------------------------------------------------------------------
    \d+                      digits (0-9) (1 or more times (matching
                             the most amount possible))
--------------------------------------------------------------------------------
   |                        OR
--------------------------------------------------------------------------------
    took                     'took '
--------------------------------------------------------------------------------
    \d*                      digits (0-9) (0 or more times (matching
                             the most amount possible))
--------------------------------------------------------------------------------
     seconds                 ' seconds'
--------------------------------------------------------------------------------
  )                        end of grouping
--------------------------------------------------------------------------------
  \.                       '.'
Related