Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/315.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
用python正则表达式提取数据_Python_Regex_Text Extraction - Fatal编程技术网

用python正则表达式提取数据

用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

我试图使用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万欧元
您可以使用捕获组获取匹配

请注意,您可以将
(?!,)\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+)
解释

  • ^
    字符串的开头
  • (TITLE-.+?-[0-9]{2}-[0-9]{2})
    Capture第1组,匹配标题部分
  • [^\s,]
    匹配除逗号以外的任何非空白字符
  • (.*(?:\r?\n(?[A-Z])*)
    Capturegroup 2,匹配所有不以大写字符开头的行
  • (?:\r?\n(?!开业)。*)*\r?\n开业日期
    匹配开业日期之前的所有行
  • (\d+.*)
    捕获组3,匹配1+个数字、空格和行的其余部分
  • (?:\r?\n(?截止日期)。*)*\r?\n截止日期
    匹配截止日期前的所有行
  • (\d+.*)
    捕获组4,匹配1+个数字和行的其余部分
  • (?:\r?\n(?!指示性预算:).*.\r?\n指示性预算:.*.
    匹配所有行,直到指示性预算:
  • (EUR\d+(?:\.\d+)\w+
    捕获第5组,匹配EUR、数字和1+字字符
|

然后,您可以将其加载到表或数据帧中

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)])