How to match text and optional repeated identifiers and group them together?

Viewed 103

I am trying to extract a block of text followed by one or more identifiers (separated by a slash) and having the identifiers be grouped with the block of text using regex in python.

Here is some dummy example data:

Lorem ipsum dolor sit amet, consectetur adipiscing elit.
 EX 0-02a
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Vestibulum eget vestibulum sapien.
Sed porta, odio id sollicitudin congue
          EX 0-04a

Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Vestibulum eget vestibulum sapien, sed porta, odio id sollicitudin congue
Lorem ipsum dolor sit amet
EX 0-01a / EX 0-05a / EX 0-07a /
EX 0-08a


Lorem ipsum dolor sit amet, 
consectetur adipiscing 
elit.
Vestibulum eget 
vestibulum sapien.
                                                      EX 3-11b

So far, I have created this regex:

(.*?)(\w{2,4} \d-\d{0,2}\w)

This successfully captures the text and one singular code, but some blocks have multiple codes (sometimes on multiple lines) and these are not grouped together as the /'s are being picked up as matches.

This is the kind of output I need:

[(Lorem ipsum dolor sit amet, consectetur adipiscing elit.), (EX 0-01a / EX 0-02a / EX 0-05b / EX 0-03a)]

Regex101: https://regex101.com/r/Wfc4nj/1

1 Answers

You could repeat the pattern matching an identifier in the capture group, and use \s+ to match 1 or more whitspace chars that also matches a newline if the identifiers can be across multiple lines.

\s*(.+?)\s*(\w{2,4} \d-\d{0,2}\w(?:\s+/\s+\w{2,4} \d-\d{0,2}\w)*)

See a regex demo and a Python demo.

For example

import re

pattern = r"\s*(.+?)\s*(\w{2,4} \d-\d{0,2}\w(?:\s+/\s+\w{2,4} \d-\d{0,2}\w)*)"

s = ("Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n"
            " EX 0-02a\n"
            "Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n"
            "Vestibulum eget vestibulum sapien.\n"
            "Sed porta, odio id sollicitudin congue\n"
            "          EX 0-04a\n\n"
            "Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n"
            "Vestibulum eget vestibulum sapien, sed porta, odio id sollicitudin congue\n"
            "Lorem ipsum dolor sit amet\n"
            "EX 0-01a / EX 0-05a / EX 0-07a /\n"
            "EX 0-08a\n\n\n"
            "Lorem ipsum dolor sit amet, \n"
            "consectetur adipiscing \n"
            "elit.\n"
            "Vestibulum eget \n"
            "vestibulum sapien.\n"
            "                                                      EX 3-11b")

print(re.findall(pattern, s, re.S))

Output

[
('Lorem ipsum dolor sit amet, consectetur adipiscing elit.', 'EX 0-02a'),
('Lorem ipsum dolor sit amet, consectetur adipiscing elit.\nVestibulum eget vestibulum sapien.\nSed porta, odio id sollicitudin congue', 'EX 0-04a'),
('Lorem ipsum dolor sit amet, consectetur adipiscing elit.\nVestibulum eget vestibulum sapien, sed porta, odio id sollicitudin congue\nLorem ipsum dolor sit amet', 'EX 0-01a / EX 0-05a / EX 0-07a /\nEX 0-08a'), 
('Lorem ipsum dolor sit amet, \nconsectetur adipiscing \nelit.\nVestibulum eget \nvestibulum sapien.', 'EX 3-11b')
]
Related