80

I would like to use a regular expression that matches any text between two strings:

Part 1. Part 2. Part 3 then more text

In this example, I would like to search for "Part 1" and "Part 3" and then get everything in between which would be: ". Part 2. "

I'm using Python 2x.

Calum
  • 1,889
  • 2
  • 18
  • 36
Carlos Muñiz
  • 1,858
  • 9
  • 25
  • 29
  • I'm trying it with my own strings but somehow something is not working. It's always returning `None`. See: `ht = re.search(pattern=r'(fun n : nat => (.*?) : 0 + n = n)', string='(fun n : nat => eq_refl : 0 + n = n)')` – Charlie Parker Jun 09 '22 at 15:14
  • for my string `import re ppt = '(fun n : nat => ?Goal : 0 + n = n)' match = re.search(r'^(.*)\?\w+(.*)$', ppt) re_ppt = f'{re.escape(match.group(1))}(.+){re.escape(match.group(2))}' print(re_ppt) print(re.match(re_ppt, "(fun n : nat => eq_refl : 0 + n = n)").groups())` – Charlie Parker Jun 09 '22 at 18:57

3 Answers3

118

Use re.search

>>> import re
>>> s = 'Part 1. Part 2. Part 3 then more text'
>>> re.search(r'Part 1\.(.*?)Part 3', s).group(1)
' Part 2. '
>>> re.search(r'Part 1(.*?)Part 3', s).group(1)
'. Part 2. '

Or use re.findall, if there are more than one occurances.

Avinash Raj
  • 172,303
  • 28
  • 230
  • 274
  • 3
    Note that the wanted answer is `". Part 2. "`, so the regular expression should be r'Part 1(.*?)Part 3'. See my answer blow. – lord63. j Sep 20 '15 at 14:06
  • 6
    Thanks for your answer, but this will not match the new line character. – Maged Saeed Feb 13 '20 at 07:26
  • do you mind explaining what the regular expression means? I'm trying it with my own strings but somehow something is not working. It's always returning `None`. See: `ht = re.search(pattern=r'(fun n : nat => (.*?) : 0 + n = n)', string='(fun n : nat => eq_refl : 0 + n = n)')` – Charlie Parker Jun 09 '22 at 15:14
  • for my string `import re ppt = '(fun n : nat => ?Goal : 0 + n = n)' match = re.search(r'^(.*)\?\w+(.*)$', ppt) re_ppt = f'{re.escape(match.group(1))}(.+){re.escape(match.group(2))}' print(re_ppt) print(re.match(re_ppt, "(fun n : nat => eq_refl : 0 + n = n)").groups())` – Charlie Parker Jun 09 '22 at 18:57
  • 1
    what if I wanted all the strings with 3 digits between Part1 and Part3? – Nuno B. Brandao Nov 21 '22 at 10:38
43

With regular expression:

>>> import re
>>> s = 'Part 1. Part 2. Part 3 then more text'
>>> re.search(r'Part 1(.*?)Part 3', s).group(1)
'. Part 2. '

Without regular expression, this one works for your example:

>>> s = 'Part 1. Part 2. Part 3 then more text'
>>> a, b = s.find('Part 1'), s.find('Part 3')
>>> s[a+6:b]
'. Part 2. '
lord63. j
  • 4,500
  • 2
  • 22
  • 30
  • How did you come up with 6, as the user said anything in between ? – Vetrivel PS Oct 04 '21 at 10:06
  • 1
    @VetrivelPS its 6 because the length of "part 1" is 6. str.find() returning the location for the first char. – ShayHa Oct 15 '21 at 13:17
  • do you mind explaining what the regular expression means? I'm trying it with my own strings but somehow something is not working. It's always returning `None`. See: `ht = re.search(pattern=r'(fun n : nat => (.*?) : 0 + n = n)', string='(fun n : nat => eq_refl : 0 + n = n)')` – Charlie Parker Jun 09 '22 at 15:14
  • for my string `import re ppt = '(fun n : nat => ?Goal : 0 + n = n)' match = re.search(r'^(.*)\?\w+(.*)$', ppt) re_ppt = f'{re.escape(match.group(1))}(.+){re.escape(match.group(2))}' print(re_ppt) print(re.match(re_ppt, "(fun n : nat => eq_refl : 0 + n = n)").groups())` – Charlie Parker Jun 09 '22 at 18:57
0

I feel these example with increasing complexity are interesting:

ppt = 'abc HERE abc'
ept = 'abc TERM abc'
re_ppt = ppt.replace('HERE', '(.+)')
print()
print(f'{re_ppt=}')
out = re.search(pattern=re_ppt, string=ept)
print(out)
print(out.groups())

ppt = 'abc HERE abc HERE abc'
ept = 'abc TERM1 abc TERM2 abc'
re_ppt = ppt.replace('HERE', '(.+)')
print()
print(f'{re_ppt=}')
out = re.search(pattern=re_ppt, string=ept)
print(out)
print(out.groups())

print()
ppt = """(fun n : nat =>
 nat_ind (fun n0 : nat => n0 + 0 = n0) ?Goal"""
print(f"{ppt=}")
ept = """(fun n : nat =>
 nat_ind (fun n0 : nat => n0 + 0 = n0) (eq_refl : 0 + 0 = 0)"""
print(f'{ept=}')
pattern_meta_var = r'\?(\w)+'
_ppt = re.sub(pattern=pattern_meta_var, repl='HERE', string=ppt)
print(f'{ppt=}')
_ppt = re.escape(_ppt)
print(f'{ppt=}')
re_ppt = _ppt.replace('HERE', '(.+)')
print(f'{re_ppt=}')
out = re.search(pattern=re_ppt, string=ept)
print(out)
print(out.groups())

print()

# sometimes the actual proof term missing won't have white spaces surrounding it but the ppt will have surrounding spaces where the hole
# would be. So in goal cames I removed the surrounding whitespaces. Then inserted a regex that accepts a hole with or
# without surrounding white spaces. That way in case the proof term in the hole does have surrounding white spaces then
# the regex hole catcher would match it anyway.
ppt = """\n   (fun (n' : nat) (IH : n' + 0 = n') => ?Goal0) n)"""
ept = """\n   (fun (n' : nat) (IH : n' + 0 = n') =>\n\teq_ind_r (fun n0 : nat => S n0 = S n') eq_refl IH : S n' + 0 = S n') n)"""
print(f"{ppt=}")
print(f'{ept=}')
pattern_meta_var = r'\s*\?(\w)+\s*'
_ppt = re.sub(pattern=pattern_meta_var, repl='HERE', string=ppt)
print(f'{_ppt=}')
_ppt = re.escape(_ppt)
print(f'{_ppt=}')
re_ppt = _ppt.replace('HERE', '\s*(.+)\s*')
print(f'{re_ppt=}')
out = re.search(pattern=re_ppt, string=ept)
print(out)
assert out is not None, f'expected two holes matched but go {out=}'
print(out.groups())

print()
ppt = """(fun n : nat =>
 nat_ind (fun n0 : nat => n0 + 0 = n0) ?Goal
   (fun (n' : nat) (IH : n' + 0 = n') => ?Goal0) n)"""
print(f"{ppt=}")
ept = """(fun n : nat =>
 nat_ind (fun n0 : nat => n0 + 0 = n0) (eq_refl : 0 + 0 = 0)
   (fun (n' : nat) (IH : n' + 0 = n') =>
    eq_ind_r (fun n0 : nat => S n0 = S n') eq_refl IH : S n' + 0 = S n') n)"""
print(f'{ept=}')
pattern_meta_var = r'\s*\?(\w)+\s*'
_ppt = re.sub(pattern=pattern_meta_var, repl='HERE', string=ppt)
print(f'{_ppt=}')
_ppt = re.escape(_ppt)
print(f'{_ppt=}')
re_ppt = _ppt.replace('HERE', '\s*(.+)\s*')
print(f'{re_ppt=}')
out = re.search(pattern=re_ppt, string=ept)
print(out)
print(out.groups())
Charlie Parker
  • 5,884
  • 57
  • 198
  • 323