2

I have following output from Protractor test and I'm trying to parse and find name of failed spec:

Specs: /var/lib/jenkins-slave/workspace//tests/js/e2e/ui_e2e/tests/test_one.js
Selenium URL: http://10.20.40.54:4444/wd/hub

..... number of different strings here....

Executed 25 of 25 specs SUCCESS in 1 min 23 secs.
-----
Specs: /var/lib/jenkins-slave/workspace//tests/js/e2e/ui_e2e/tests/test_two.js

..... number of different strings here....

UnknownError: Due to a previous error, this job has already finished. You can learn more at

I'm using following regex:

(?:Specs:)(?:[\s\S])*(?=UnknownError(.*?))

However, it matches too wide section from first string, swallowing string with test_two.js.

How can I avoid swallowing and narrow match to have it like:

Specs: /var/lib/jenkins-slave/workspace//tests/js/e2e/ui_e2e/tests/test_two.js

..... number of different strings here....

UnknownError: Due to a previous error, this job has already finished. You can learn more at
Wiktor Stribiżew
  • 607,720
  • 39
  • 448
  • 563

1 Answers1

2

I think you are not looking for a "nearest" match, but for the shortest "window" between the start and end delimiters.

You may use

/^Specs:(?:(?!^Specs:)[\s\S])*UnknownError:\s*(.*)/gm

Or its more efficient unrolled variant:

/^Specs:.*(?:\r?\n(?!Specs:).*)*UnknownError:\s*(.*)/gm

See the regex demo

Details:

  • ^ - start of a line
  • Specs: - a sequence of literal chars
  • (?:(?!^Specs:)[\s\S])* - a tempered greedy token matching any char that does not start a sequence of a line start, Specs: (in the unrolled variant, the same is done with .*(?:\r?\n(?!Specs:).*)* subpattern)
  • UnknownError: - a substring
  • \s* - 0+ whitespaces
  • (.*) - Group 1 capturing any zero or more chars other than line break chars.
Wiktor Stribiżew
  • 607,720
  • 39
  • 448
  • 563