What is the correct way of grabbing an inner string in regular expressions for Python for multiple conditions

Viewed 58

I would like to return all strings within the specified starting and end strings.

Given a string libs = 'libr(lib1), libr(lib2), libr(lib3), req(reqlib), libra(nonlib)'.

From the above libs string I would like to search for strings that are in between libr( and ) or the string between req( and ).

I would like to return ['lib1', 'lib2', 'lib3', 'reqlib']

import re 
libs = 'libr(lib1), libr(lib2), libr(lib3), req(reqlib), libra(nonlib)'
pat1 = r'libr+\((.*?)\)'
pat2 = r'req+\((.*?)\)'
pat = f"{pat1}|{pat2}"
re.findall(pat, libs)

The code above currently returns [('lib1', ''), ('lib2', ''), ('lib3', ''), ('', 'reqlib')] and I am not sure how I should fix this.

3 Answers

Try this regex

(?:(?<=libr\()|(?<=req\())[^)]+

Click for Demo

Click for Code

Explanation:

  • (?:(?<=libr\()|(?<=req\())
    • (?<=libr\() - positive lookbehind that matches the position which is immediately preceded by text libr(
    • | - or
    • (?<=req\() - positive lookbehind that matches the position which is immediately preceded by text req(
  • [^)]+ - matches 1+ occurrences of any character which is not a ). So, this will match everything until it finds the next )

You can do it like this:

pat1 = r'(?<=libr\().*?(?=\))'
pat2 = r'(?<=req\().*?(?=\))'

It uses positive lookbehind (?<=) and positive lookahead (?=).

  • .*? : selects all characters in between. I'll name it "content"
  • (?<=libr\() : "content" must be preceded by libr( (we escape the ( )
  • ?(?=\)) : content must be followed by ) ( ( is escaped too)

Complete code:

import re 
libs = 'libr(lib1), libr(lib2), libr(lib3), req(reqlib), libra(nonlib)'
pat1 = r'(?<=libr\().*?(?=\))'
pat2 = r'(?<=req\().*?(?=\))'
pat = f"{pat1}|{pat2}"
result = re.findall(pat, libs)
print(result)

Output:

['lib1', 'lib2', 'lib3', 'reqlib']

I think a common way to do so is using alternation in the word you would want to be preceding the pattern you like to capture:

\b(?:libr|req)\(([^)]+)

See the online demo

  • \b - Word-boundary.
  • (?: - Open non-capture group:
    • libr|req - Match "libr" or "req".
    • ) - Close non-capture group.
  • \( - A literal opening paranthesis.
  • ( - Open a capture group:
    • [^)]+ - Match 1+ characters apart from closing paranthesis.
    • ) - Close capture group.

A python demo:

import re
libs = 'libr(lib1), libr(lib2), libr(lib3), req(reqlib), libra(nonlib)'
lst = re.findall(r'\b(?:libr|req)\(([^)]+)', libs)
print(lst)

Prints:

['lib1', 'lib2', 'lib3', 'reqlib']
Related