从使用 Python 3.12 的文本文件中,如何从具有多个括号的行中提取子字符串:
line1: 'group(something)'
line2: 'other(something) and group(something,something,something) and not group(something,something)'
我只对“group()”或“not group()”中的“某物”感兴趣。
def find_within(search_in, search_for, until):
return search_in[search_in.find(search_for) + len(search_for) : search_in.find(until)]
group1 = find_within(line1, 'group(', ')') # extracting group from the first line
group2 = find_within(line2, 'and group(', ')') # extracting group from the second line
not_group = find_within(line2, 'not group(', ')') # extracting 'not group' from the second line
此函数可以处理从仅具有单个“group()”(如 line1)的行中进行提取,但不能处理从具有多个项目(如 line2)的行中进行提取(它将返回 null)。我尝试用
.find()
替换最后一个 .rfind()
:
def find_within(search_in, search_for, until):
return search_in[search_in.find(search_for) + len(search_for) : search_in.rfind(until)]
但是输出是:
'某事,某事,某事)而不是组(某事,某事'
虽然我期待:
“某事,某事,某事”
.find()
查找括号的第一次出现,因此当我从字符串中间的“group(something)”中查找“something”时,.find()
会查看前面一对括号中的右括号'group(something)',因此返回 ''。并且 .rfind()
查找最后一次出现的括号,因此提取直到最后一个括号的所有内容。
有更好的方法使用
.find()
还是我需要正则表达式?
我认为您可能缺少的是,您可以给
str.find()
第二个可选整数参数(str.find(target, offset)
)来告诉您要从哪里开始搜索。
因此,在下面的示例中,我们使用
start = 0
作为字符串的开头
如果找到目标字符串,我们将
start
前进 offset
,以指向刚刚过去 '(' 字符的字符。然后我们从该位置向前搜索,找到下一个 ')' 字符,即我们的 stop
位置
那么括号里的内容就是从
stop
到start
的切片。 在我的示例中,我将 contents
附加到 list
,但您可以将其打印出来,或者您需要的任何内容
最终
str.find()
将返回-1,表示没有进一步的匹配,因此我们从函数返回
text = "group(a, b, c) and group(d, e, f) and not group(g, h, i)"
def findit(target, text):
"""look for target followed by (
save the text following the ( until the next )
append that text to results
when target doesn't match any more return results"""
results = []
target += '(' #add open parenthesis after target
offset = len(target)
start = 0
while True:
start = text.find(target, start)
#print(start)
if start == -1:
break
start += offset
stop = text.find(')', start)
contents = text[start:stop]
results.append(contents)
return results
print("\ngroup")
print(findit('group', text))
print("\nand group")
print(findit('and group', text))
print("\nnot group")
print(findit('not group', text))
该程序将产生以下输出:
group
['a, b, c', 'd, e, f', 'g, h, i']
and group
['d, e, f']
not group
['g, h, i']
您可以使用模式来查找预期输出:
\b(group)\s*\(([^)]+)\)|\s*(\band\s+group)\(([^)]+)\)|\s*(\band\s+not\s+group)\(([^)]+)\)|\s*\b(other)\(([^)]+)\)
import re
def _find(p, s):
return re.findall(p, s)
p = r'\b(group)\s*\(([^)]+)\)|\s*(\band\s+group)\(([^)]+)\)|\s*(\band\s+not\s+group)\(([^)]+)\)|\s*\b(other)\(([^)]+)\)'
s = """
line1: 'group(something)'
line2: 'other(something) and group(something,something,something) and not group(something,something)'
I'
"""
print(_find(p, s))
[('group', 'something', '', '', '', '', '', ''), ('', '', '', '', '', '', 'other', 'something'), ('', '', 'and group', 'something,something,something', '', '', '', ''), ('', '', '', '', 'and not group', 'something,something', '', '')]
\(([^)]+)\)
:这四组就是数值。您可以使用简单的模式并获取所有键和值,然后继续执行文本处理任务:
import re
def _find(p, s, as_dict=False):
matches = re.findall(p, s)
if as_dict:
return {m[0].strip(): m[1] for m in matches}
return matches
p = r"\s*([^(']+)\s*\(([^)]+)\)"
s = """
line1: 'group(something)'
line2: 'other(something) and group(something,something,something) and not group(something,something)'
I'
"""
print(_find(p, s))
print(_find(p, s, as_dict=True))
[('group', 'something'), ('other', 'something'), ('and group', 'something,something,something'), ('and not group', 'something,something')]
{'group': 'something', 'other': 'something', 'and group': 'something,something,something', 'and not group': 'something,something'}
第二种模式非常简单:
([^(']+)
:捕获组 1 找到密钥。\s*\(([^)]+)\)
:捕获组 2 找到值。[^(']+
:表示允许使用所有字符,除了(即^
)这两个[(']
,然后一次或多次(即+
)。([^)]+)
:表示允许使用所有字符,除了(即^
)一个字符,即字符类中的)
(即[]
)。