Finding pattern to extract text from a string using regular expession

Viewed 53

I have data which I'm reading in a string format as

>>> 26 24 16  Panelboards  10/05/18 26 26 00i  Power Distribution Units – Install  10/05/18

I want to seperate '26 24 16', 'Panelboards', 10/05/18 and '26 26 00i', 'Power Distribution Units – Install', 10/05/18 as sub section, name, and date.

Also after every date, new item can begin. In this case, after 10/05/18, new sub section begins.

I have used regular expression to filter out sub section as but it creates unstructuring in my data.

re.split(r'\d\d \d\d \d\d',sentence)

If anyone has solution to efficiently retrieve these 3 features for two items.

Also, I can't use two spaces as regex due to change in structural file

3 Answers

Try:

s = """26 24 16  Panelboards  10/05/18 26 26 00i  Power Distribution Units – Install  10/05/18"""

out = re.split(r"\s{2,}", s)
print(out)

Prints:

['26 24 16', 'Panelboards', '10/05/18 26 26 00i', 'Power Distribution Units – Install', '10/05/18']

EDIT: If you want to split the 2nd item, use str.split() with maxsplit=1:

from itertools import chain

s = """26 24 16  Panelboards  10/05/18 26 26 00i  Power Distribution Units – Install  10/05/18"""

out = re.split(r"\s{2,}", s)
out = list(chain(out[:2], out[2].split(maxsplit=1), out[3:]))
print(out)

Prints:

['26 24 16', 'Panelboards', '10/05/18', '26 26 00i', 'Power Distribution Units – Install', '10/05/18']

You can use

\b(?P<subsection>\d+(?:\s+\d\w*)+)\s+(?P<name>.*?)\s+(?P<date>\d{1,2}/\d{1,2}/\d{2})\b

See the regex demo. Details:

  • \b - word boundary
  • (?P<subsection>\d+(?:\s+\d\w*)+) - Group "subsection": one or more digits and then one or more occurrences of one or more whitespaces followed with a digit and then zero or more word chars
  • \s+ - one or mor whitespaces
  • (?P<name>.*?) - Group "name": zero or more chars other than line break chars as few as possible
  • \s+ - one or mor whitespaces
  • (?P<date>\d{1,2}/\d{1,2}/\d{2}) - Group "date": one or two digits, /, one or two digits, /, two digits
  • \b - word boundary

See a Python demo:

import re
pattern = r"\b(?P<subsection>\d+(?:\s+\d\w*)+)\s+(?P<name>.*?)\s+(?P<date>\d{1,2}/\d{1,2}/\d{2})\b"
text = "26 24 16  Panelboards  10/05/18 26 26 00i  Power Distribution Units – Install  10/05/18"
print([x.groupdict() for x in re.finditer(pattern, text)])

Output:

[
 {'subsection': '26 24 16', 'name': 'Panelboards', 'date': '10/05/18'}, 
 {'subsection': '26 26 00i', 'name': 'Power Distribution Units – Install', 'date': '10/05/18'}
]

Be as specific as you can:

/^(\d\d \d\d \d\d) +(.+?) +(\d\d\/\d\d\/\d\d)$/

Match group 1 for the subsection, 2 for the name and 3 for the date.

If you need to split the string first into each line, you could hook that into the end of the date:

\/\d\d\s
Related