How do I split a string if there is a positive lookahead and a positive lookbehind but not a delimiter?

Viewed 914

Example:

s = "Thisissometext andthisissometext"

I want to split the text between "is" and "some":

["Thisis", "sometext andthisis", "sometext"]

If I do this:

re.split("(?<=is)s(?=ome)", s)
-->    ['Thisis', 'ometext andthisis', 'ometext']

no 's'

If i do this

re.split("(?<=is)(s)(?=ome)", s)
-->   ['Thisis', 's', 'ometext andthisis', 's', 'ometext']

If i do this

re.split("(?<=is)(?=some)", s)
-->   ValueError: split() requires a non-empty pattern match.

How can I split a string if there is no delimiter??

3 Answers

You need the newer regex module which supports empty splits:

import regex as re

s = "Thisissometext andthisissometext"

print(re.split(r"(?V1)(?<=is)(?=some)", s))
# ['Thisis', 'sometext andthisis', 'sometext']

Note the (?V1) here which enables the newer behaviour. This can be set via a flag as well:

print(re.split(r"(?<=is)(?=some)", s, flags = re.VERSION1))

A simple and faster approach, which works if you know a non existing character in the text, '@' here:

s.replace('issome','is@some').split('@')
# ['Thisis', 'sometext andthisis', 'sometext']

tests :

In [300]: %timeit s.replace('issome','is@some').split('@')
976 ns ± 21.6 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

In [301]: %timeit regex.split(r"(?V1)(?<=is)(?=some)", s)
7.36 µs ± 145 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

In [302]: %timeit re.findall(r'[\w\s]+?(?:is(?=some)|$)', s)
4.28 µs ± 97.5 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

Instead of using split, here is a regex that you can use in re.findall to get your job done:

>>> s = "Thisissometext andthisissometext"
>>> print re.findall(r'[\w\s]+?(?:is(?=some)|$)', s)
['Thisis', 'sometext andthisis', 'sometext']

RegEx Demo

RegEx Breakup:

  • [\w\s]+?: Match 1+ word or space characters (non-greedy)
  • (?:: Start a non-capturing group
    • is: Match literal is
    • (?=some): That must be followed by some
    • |: OR
    • $: it is end of string
  • ): End non-capturing group
Related