Stop capturing after reaching a line with only uppercase letters

Viewed 47

I am trying to capture only the words between titles that are always all caps (in the example below, 'SONG' and 'AT BAIA'). When using this, I will know what the first title is (i.e. 'SONG'), but I won't know what the second title is (i.e. 'AT BAIA').

Example

And I lie listening awake?    
SONG    
You are as gold    
The half-opened flowers    
For your face is as fair as rain,    
Yet as rain that lies clear    
Casts light for a shadow.    
AT BAIA    
I should have thought

I've managed to capture everything below 'SONG' using:

SONG\s*((.*\s.*)*)

But can't figure out how to stop when I reach a line with only capital letters.

Any help would be greatly appreciated.

3 Answers

You could match SONG followed by capturing in a group all the lines that do not start with 2 uppercase chars

^SONG\b.*((?:\r?\n(?![A-Z]{2}).*)*)

Regex demo

Or if the line can contain only contain captital letters and should also start with one:

^SONG\b.*((?:\r?\n(?![A-Z][A-Z ]*$).*)*)
  • ^ Start of string
  • SONG\b.* Match Song, word boundary and the rest of the line
  • ( Capture group 1
    • (?: Non capture group
      • \r?\n(?![A-Z][A-Z ]*$).* Match a newline and the rest of the line if it does not contain only uppercase chars
    • )* Close the group and match all the lines
  • ) Close group 1

Regex demo | Python demo

You can use the following:

SONG[\s\S]*(?=^[A-Z][A-Z ]+$)

Demo

You will also need the re.MULTILINE flag for this to work correctly.

I'd suggest a more simple regex SONG(?:.|\n)*[A-Z]{3,}\s+\n

  • start with SONG
  • read any content
  • stop when the line ends with an uppercase word (at least 3 uppercase letter, you can choose the size you need)

REGEX DEMO

Related