Regex between digits and strings

Viewed 101

I am trying to extract all digits referring to teaching experience, which should be 8, 17, 7. I have tried (years.*?teaching.*?:.*?[0-9]+|\d+.+teaching) but it grabs everything from the first digit because of the second condition.

Sample text:

10+ years small business ownership, 10+ years sme consulting, 10+ years corporate/vocational business training, 8 years teaching experience, years of teaching experience: 17, 7+ years teaching/Corporate Training experience

4 Answers

Keeping your regex as it is, it would be nice to approach it in a different way. I would rather break things apart and then try the regex on smaller string instead.

import re

input = '10+ years small business ownership, 10+ years sme consulting, 10+ years corporate/vocational business training, 8 years teaching experience, years of teaching experience: 17, 7+ years teaching/Corporate Training experience'

regex = re.compile('(years.*?teaching.*?:.*?[0-9]+|\d+.+teaching)');

lines = input.split(',')
filteredLines = filter(lambda line: 'teaching' in line, lines)
experiences = map(lambda line: regex.match(line.strip()).group(), filteredLines);

print(list(experiences))

You could further modify this to fit your needs.

With the following assumptions:

  • Each comma separated substring contains not more than one number
  • teaching is always related to experience years in separated substrings

An idea with a lookahad (for use with re.findall , re.I flag to ignore case)

re.findall(r"(?:,|^)(?=[^,]*?teaching)[^\d,]*(\d+\+?)", s, flags=re.I)
  • (?:,|^) Starting point is either ^ start of string or a comma
  • (?=[^,]*?teaching) Condition to check if teaching occurs before next ,
  • On success [^\d,]*(\d+\+?) capture the number and optional + to the first group

See this demo at regex101 (more info on right side) or a Python demo at tio.run

Motivated by @bobble bubble's encouragement, I propose this regex (polished up after bobble bubble's comment):

([0-9]+).{1,15}teaching|teaching.{1,15}?([0-9]+)

Given the proximity of "teaching" to the number of years this regex splits the match in two parts:

  1. "teaching" comes after number of year but in close reach (any character within 1 to 15 positions).
  2. "teaching" comes first; note .{1,15}?; ? at the end is not greedy otherwise it would match also "1" in "experience: 17"

The drawback is it generates two groups. You can get rid of it using python as follows:

import re

s = "10+ years small business ownership, 10+ years sme consulting, 10+ years corporate/vocational business training, 8 years teaching experience, years of teaching experience: 17, 7+ years teaching/Corporate Training experience"

matches = re.findall(r"([0-9]+).{1,15}teaching|teaching.{1,15}?([0-9]+)", s)

matches = [int(x) if x != '' else int(y) for (x, y) in matches]

print(matches)  # A list of teaching years as int
print(re.sub(r'.*?training,\s','', txt))

8 years teaching experience, years of teaching experience: 17, 7+ years teaching/Corporate Training experience
Related