# python – How to extract the substring between two markers?

## The Question :

373 people think this question is useful

Let’s say I have a string 'gfgfdAAA1234ZZZuijjk' and I want to extract just the '1234' part.

I only know what will be the few characters directly before AAA, and after ZZZ the part I am interested in 1234.

With sed it is possible to do something like this with a string:

echo "$STRING" | sed -e "s|.*AAA$$.*$$ZZZ.*|\1|"  And this will give me 1234 as a result. How to do the same thing in Python? The Question Comments : ## The Answer 1 659 people think this answer is useful Using regular expressions – documentation for further reference import re text = 'gfgfdAAA1234ZZZuijjk' m = re.search('AAA(.+?)ZZZ', text) if m: found = m.group(1) # found: 1234  or: import re text = 'gfgfdAAA1234ZZZuijjk' try: found = re.search('AAA(.+?)ZZZ', text).group(1) except AttributeError: # AAA, ZZZ not found in the original string found = '' # apply your error handling # found: 1234  ## The Answer 2 121 people think this answer is useful >>> s = 'gfgfdAAA1234ZZZuijjk' >>> start = s.find('AAA') + 3 >>> end = s.find('ZZZ', start) >>> s[start:end] '1234'  Then you can use regexps with the re module as well, if you want, but that’s not necessary in your case. ## The Answer 3 79 people think this answer is useful ### regular expression import re re.search(r"(?<=AAA).*?(?=ZZZ)", your_text).group(0)  The above as-is will fail with an AttributeError if there are no “AAA” and “ZZZ” in your_text ### string methods your_text.partition("AAA")[2].partition("ZZZ")[0]  The above will return an empty string if either “AAA” or “ZZZ” don’t exist in your_text. PS Python Challenge? ## The Answer 4 17 people think this answer is useful Surprised that nobody has mentioned this which is my quick version for one-off scripts: >>> x = 'gfgfdAAA1234ZZZuijjk' >>> x.split('AAA')[1].split('ZZZ')[0] '1234'  ## The Answer 5 15 people think this answer is useful import re print re.search('AAA(.*?)ZZZ', 'gfgfdAAA1234ZZZuijjk').group(1)  ## The Answer 6 13 people think this answer is useful you can do using just one line of code >>> import re >>> re.findall(r'\d{1,5}','gfgfdAAA1234ZZZuijjk') >>> ['1234']  result will receive list… ## The Answer 7 8 people think this answer is useful You can use re module for that: >>> import re >>> re.compile(".*AAA(.*)ZZZ.*").match("gfgfdAAA1234ZZZuijjk").groups() ('1234,)  ## The Answer 8 5 people think this answer is useful With sed it is possible to do something like this with a string: echo "$STRING" | sed -e "s|.*AAA$$.*$$ZZZ.*|\1|"

And this will give me 1234 as a result.

You could do the same with re.sub function using the same regex.

>>> re.sub(r'.*AAA(.*)ZZZ.*', r'\1', 'gfgfdAAA1234ZZZuijjk')
'1234'



In basic sed, capturing group are represented by $$..$$, but in python it was represented by (..).

5 people think this answer is useful

In python, extracting substring form string can be done using findall method in regular expression (re) module.

>>> import re
>>> s = 'gfgfdAAA1234ZZZuijjk'
>>> ss = re.findall('AAA(.+)ZZZ', s)
>>> print ss
['1234']



4 people think this answer is useful
>>> s = '/tmp/10508.constantstring'
>>> s.split('/tmp/')[1].split('constantstring')[0].strip('.')



4 people think this answer is useful

You can find first substring with this function in your code (by character index). Also, you can find what is after a substring.

def FindSubString(strText, strSubString, Offset=None):
try:
Start = strText.find(strSubString)
if Start == -1:
else:
if Offset == None:
Result = strText[Start+len(strSubString):]
elif Offset == 0:
return Start
else:
AfterSubString = Start+len(strSubString)
Result = strText[AfterSubString:AfterSubString + int(Offset)]
return Result
except:
return -1

# Example:

Text = "Thanks for contributing an answer to Stack Overflow!"
subText = "to"

print("Start of first substring in a text:")
start = FindSubString(Text, subText, 0)
print(start); print("")

print("Exact substring in a text:")
print(Text[start:start+len(subText)]); print("")

print("What is after substring \"%s\"?" %(subText))
print(FindSubString(Text, subText))

Text = "gfgfdAAA1234ZZZuijjk"
subText1 = "AAA"
subText2 = "ZZZ"

AfterText1 = FindSubString(Text, subText1, 0) + len(subText1)
BeforText2 = FindSubString(Text, subText2, 0)



4 people think this answer is useful
text = 'I want to find a string between two substrings'
left = 'find a '
right = 'between two'

print(text[text.index(left)+len(left):text.index(right)])



Gives

string



3 people think this answer is useful

Just in case somebody will have to do the same thing that I did. I had to extract everything inside parenthesis in a line. For example, if I have a line like ‘US president (Barack Obama) met with …’ and I want to get only ‘Barack Obama’ this is solution:

regex = '.*$$(.*?)$$.*'
matches = re.search(regex, line)
line = matches.group(1) + '\n'



I.e. you need to block parenthesis with slash \ sign. Though it is a problem about more regular expressions that Python.

Also, in some cases you may see ‘r’ symbols before regex definition. If there is no r prefix, you need to use escape characters like in C. Here is more discussion on that.

2 people think this answer is useful

Using PyParsing

import pyparsing as pp

word = pp.Word(pp.alphanums)

s = 'gfgfdAAA1234ZZZuijjk'
rule = pp.nestedExpr('AAA', 'ZZZ')
for match in rule.searchString(s):
print(match)



which yields:

[['1234']]

0 people think this answer is useful

Here’s a solution without regex that also accounts for scenarios where the first substring contains the second substring. This function will only find a substring if the second marker is after the first marker.

def find_substring(string, start, end):
len_until_end_of_first_match = string.find(start) + len(start)
after_start = string[len_until_end_of_first_match:]
return string[string.find(start) + len(start):len_until_end_of_first_match + after_start.find(end)]



0 people think this answer is useful

Another way of doing it is using lists (supposing the substring you are looking for is made of numbers, only) :

string = 'gfgfdAAA1234ZZZuijjk'
numbersList = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
output = []

for char in string:
if char in numbersList: output.append(char)

print(f"output: {''.join(output)}")
### output: 1234



0 people think this answer is useful

Typescript. Gets string in between two other strings.

Searches shortest string between prefixes and postfixes

prefixes – string / array of strings / null (means search from the start).

postfixes – string / array of strings / null (means search until the end).

public getStringInBetween(str: string, prefixes: string | string[] | null,
postfixes: string | string[] | null): string {

if (typeof prefixes === 'string') {
prefixes = [prefixes];
}

if (typeof postfixes === 'string') {
postfixes = [postfixes];
}

if (!str || str.length < 1) {
throw new Error(str + ' should contain ' + prefixes);
}

let start = prefixes === null ? { pos: 0, sub: '' } : this.indexOf(str, prefixes);
const end = postfixes === null ? { pos: str.length, sub: '' } : this.indexOf(str, postfixes, start.pos + start.sub.length);

let value = str.substring(start.pos + start.sub.length, end.pos);
if (!value || value.length < 1) {
throw new Error(str + ' should contain string in between ' + prefixes + ' and ' + postfixes);
}

while (true) {
try {
start = this.indexOf(value, prefixes);
} catch (e) {
break;
}
value = value.substring(start.pos + start.sub.length);
if (!value || value.length < 1) {
throw new Error(str + ' should contain string in between ' + prefixes + ' and ' + postfixes);
}
}

return value;
}



-1 people think this answer is useful

One liners that return other string if there was no match. Edit: improved version uses next function, replace "not-found" with something else if needed:

import re
res = next( (m.group(1) for m in [re.search("AAA(.*?)ZZZ", "gfgfdAAA1234ZZZuijjk" ),] if m), "not-found" )



My other method to do this, less optimal, uses regex 2nd time, still didn’t found a shorter way:

import re
res = ( ( re.search("AAA(.*?)ZZZ", "gfgfdAAA1234ZZZuijjk") or re.search("()","") ).group(1) )