用python正则表达式提取数据
我试图使用python从txt文件(见下面的示例文本)中提取数据。考虑到标题可以在一条直线上,分成两条线,甚至在中间用空行分割(Title 1)。 我想要实现的是提取信息以存储在如下表中: 代码 标题 开幕日期 截止日期 预算 标题-SDFSD-DFDS-SFDS-01-01 这是标题1,它在两条直线上分开,中间有一条空行。 四月十五日至二十一日 8月26日至21日 2000万欧元 标题-SDFSD-DFDS-SFDS-01-02 这是一行中的标题2 三月十五日至二十一日 8月17日至21日 1500万欧元 标题-SDFSD-DFDS-SFDS-01-03 这是标题3,太长了,需要两行 5月15日至21日 九月二十六日至二十一日 500万欧元用python正则表达式提取数据,python,regex,text-extraction,Python,Regex,Text Extraction,我试图使用python从txt文件(见下面的示例文本)中提取数据。考虑到标题可以在一条直线上,分成两条线,甚至在中间用空行分割(Title 1)。 我想要实现的是提取信息以存储在如下表中: 代码 标题 开幕日期 截止日期 预算 标题-SDFSD-DFDS-SFDS-01-01 这是标题1,它在两条直线上分开,中间有一条空行。 四月十五日至二十一日 8月26日至21日 2000万欧元 标题-SDFSD-DFDS-SFDS-01-02 这是一行中的标题2 三月十五日至二十一日 8月17日至21日 1
您可以使用捕获组获取匹配 请注意,您可以将
(?!,)\S
写成[^\S,]
根据示例中的行:
^(TITLE-.+?-[0-9]{2}-[0-9]{2})[^\s,] (.*(?:\r?\n(?![A-Z]).*)*)(?:\r?\n(?!Opening).*)*\r?\nOpening date (\d+ .*)(?:\r?\n(?!Deadline).*)*\r?\nDeadline (\d+ .*)(?:\r?\n(?!Indicative budget:).*)*\r?\nIndicative budget: .*?(EUR \d+(?:\.\d+)? \w+)
解释
字符串的开头^
Capture第1组,匹配标题部分(TITLE-.+?-[0-9]{2}-[0-9]{2})
匹配除逗号以外的任何非空白字符[^\s,]
Capturegroup 2,匹配所有不以大写字符开头的行(.*(?:\r?\n(?[A-Z])*)
匹配开业日期之前的所有行(?:\r?\n(?!开业)。*)*\r?\n开业日期
捕获组3,匹配1+个数字、空格和行的其余部分(\d+.*)
匹配截止日期前的所有行(?:\r?\n(?截止日期)。*)*\r?\n截止日期
捕获组4,匹配1+个数字和行的其余部分(\d+.*)
匹配所有行,直到指示性预算:(?:\r?\n(?!指示性预算:).*.\r?\n指示性预算:.*.
捕获第5组,匹配EUR、数字和1+字字符(EUR\d+(?:\.\d+)\w+
with open('doubt2.txt','r', encoding="utf-8") as f:
f_contents = f.read()
pattern = re.compile(r"^(TITLE-.+?-[0-9]{2}-[0-9]{2})[^\s,] (.*(?:\r?\n(?![A-Z]).*)*)(?:\r?\n(?!Opening).*)*\r?\nOpening date (\d+ .*)(?:\r?\n(?!Deadline).*)*\r?\nDeadline (\d+ .*)(?:\r?\n(?!Indicative budget:).*)*\r?\nIndicative budget: .*?(EUR \d+(?:\.\d+)? \w+)", re.MULTILINE)
matches = pattern.findall(f_contents)
df = pd.DataFrame(matches, columns = ['Code', 'Title', 'Opening date', 'Deadline', 'Budget'])
df['Title'] = df['Title'].str.replace('[\r\n]+',' ')
print(df)
输出
对捕获组使用正则表达式。使用
re.DOTALL
标志允许*
跨多行匹配,因此您可以捕获多行标题。并使用惰性量词来避免匹配太长
import csv
import re
pattern = re.compile(r'^(TITLE-.+?-\d{2}-\d{2})\S*\s*(.*?)^Conditions.*?^Opening date (\d{1,2} \w+ \d{4})\s*?^Deadline (\d{1,2} \w+ \d{4})\s*^Indicative budget:.*?(EUR [\d.]+ \w+)', re.MULTILINE | re.DOTALL)
matches = pattern.finditer(f_contents)
with open("result.csv", "w") as outfile:
csvfile = csv.writer(outfile)
csvfile.writerow(['Code', 'Title', 'Opening date', 'Deadline', 'Budget'])
for match in matches:
csvfile.writerow([match.group(1), match.group(2).replace('\n', ' '), match.group(3), match.group(4), match.group(5)])
使用
pattern.findall()
,它将返回一个字符串列表。您如何判断一个标题拆分为两行?请将表格作为文本发布,而不是屏幕截图。请参见条件
是否总是标题后第一段的开头?您可以使用re.DOTALL
和re.MULTILINE
标志跨多行匹配,直到匹配完成为止。@fourthbird感谢您的指示。我希望我以前知道regex101.com网站,我花了两天时间才学会基本的正则表达式。尽管如此,我还是要检查它是如何工作的,这是令人印象深刻的。。。非常感谢你。我尝试了你的代码,它告诉我,module'csv'没有属性'writerow'
我需要安装一个特殊的包吗?对不起,应该是csvfile.writerow
re.DOTALL
在regex101.com上被称为single line
。如果它不总是一个空格,请使用\s+
匹配任何空格,这将匹配新线。再次感谢。我知道评论不是针对这一点的,但它不允许我将解决方案标记为有用。感谢您访问regex101网站。com@nekovolta如果单击有助于解决问题,则可以将其视为已接受✓ 在它的左边。注意,你得到2个接受一个解决方案。我不知道我不能同时接受两个解决方案。我喜欢这两种方法,但由于CSV文件的生成,可能另一种方法更适合。但是,通过您的解释,我更好地理解了正则表达式。我的印象是我已经投票支持你的回答:)@nekovolta?
使*
在匹配-[0-9]{2}-[0-9]{2}
import csv
import re
pattern = re.compile(r'^(TITLE-.+?-\d{2}-\d{2})\S*\s*(.*?)^Conditions.*?^Opening date (\d{1,2} \w+ \d{4})\s*?^Deadline (\d{1,2} \w+ \d{4})\s*^Indicative budget:.*?(EUR [\d.]+ \w+)', re.MULTILINE | re.DOTALL)
matches = pattern.finditer(f_contents)
with open("result.csv", "w") as outfile:
csvfile = csv.writer(outfile)
csvfile.writerow(['Code', 'Title', 'Opening date', 'Deadline', 'Budget'])
for match in matches:
csvfile.writerow([match.group(1), match.group(2).replace('\n', ' '), match.group(3), match.group(4), match.group(5)])