我已经用python与re
模块结合编写了一个脚本,以从少量文本中抓取一些内容。如果我单独尝试,我定义的模式可以成功找到并获取它们。
但是,我的问题是如何在循环中使用这些模式一次性拍摄它们?最重要的是,并非所有文本块中的所有字段都可用。
我尝试过(以下所有模式都是有效的):
import re
content="""
Name: Larry King
Telephone: 514 353-4119
Website: http://www.lexor.biz
Name: Allen Smith
Telephone: 819 986-3429
Website: http://aefournier.com
Email: aefournier@videotron.ca
Name: Paul adams
Telephone: 1-819-477-6656
Email: info@lexor.biz
"""
pattern = re.compile(r"Name:\s+(.*)")
# pattern = re.compile(r"Telephone:\s+(.*)")
# pattern = re.compile(r"Email:\s+(.*)")
# pattern = re.compile(r"Website:\s+(.*)")
for item in pattern.finditer(content):
print(item.group(1))
我期望第一个容器具有输出(电子邮件在第一个块中丢失,因此空白字段应该用N/A
填充):
Larry King 514 353-4119 http://www.lexor.biz N/A
and so on--
答案 0 :(得分:2)
如果您输入的内容始终是相同的顺序(名称,电话,网站,电子邮件),但后面的一些可选内容是可选的,那么您可以使用正则表达式进行输入。但这可能不是一个好主意。
我们可以将这四个模式连接起来,并在它们之间使用适当的空格模式(我使用\n
,该模式适用于您发布的示例,但我不确定它是否正确),并标记后三个可选项,方法是将它们放在一个非捕获组中并附加一个?
:
Name:\s+(.*)\n(?:Telephone:\s+(.*)\n)?(?:Website:\s+(.*)\n)?(?:Email:\s+(.*)\n)?
您可以in action at regex101看到它。
请注意,例如,最后一场比赛没有第3组,只有第1、2和4组。
(给这些组?P<names>
可能会更好一些,因此您可以通过名称来引用它们。)
但是,通过将其视为由空白行分隔的块序列(每个块均采用Header:Value格式)来解决,则要容易得多。您甚至不需要正则表达式;只是遍历了可迭代的字符串。
或者,更简单地说,使用itertools.groupby
为您将其分成多个块。非空行是真实的,空行是虚假的,所以只需按真实性分组:
lines = content.splitlines()
for nonempty, group in itertools.groupby(lines, bool):
if nonempty:
print('New Entry')
for line in group:
header, value = line.split(':', 1)
print(header.strip(), value.strip())
或者,假设您想将这些条目实际收集到某种结构中,例如按名称键入的dict的dict:
def parse(lines):
for nonempty, group in itertools.groupby(lines, bool):
if nonempty:
pairs = (line.split(':', 1) for line in group)
yield {header.strip(): value.strip() for header, value in pairs}
entries = {entry['Name']: entry for entry in parse(content.splitlines())}