除了所有输入数据外,还将re.findall()输出到CSV

时间:2019-06-30 11:18:25

标签: python regex csv findall postal-code

我正在尝试将regex .findall()搜索的结果保存到csv中,但是很难将结果附加到输出文件中。

由于我对Python还是很陌生,所以我试图将这个问题限制为仅使用csv和re库-但是,如果有一种更简单的方法(例如,在熊猫中),这也将有所帮助。


  1. 如何将输入CSV的全部内容复制到输出CSV并将邮政编码/找到的正则表达式添加到找到它的行?

  2. 我是否有任何明显形式的错误检查或其他遗漏的东西?

  3. 是否存在一种更好的方法,可以将输入CSV的标头自动添加到输出CSV而无需显式指定它们?

  4. 是否可以使用DictWriter做到这一点?正如我最初尝试的那样。


import csv, re

pattern = r'[A-Z]{1,2}[0-9R][0-9A-Z]?[0-9][A-Z]{2}'
postcodes = []
with open(r'Postcode/addressin.csv', 'r') as csvinput:
    csv_reader = csv.DictReader(csvinput)

    with open(r'Postcode/addressout.csv', 'w', newline='') as csvoutput:
        fieldnames = ['Address', 'Name']
        csv_writer = csv.writer(csvoutput)

        csv_writer.writerow(fieldnames)

        for line in csv_reader:
            postcodes = re.findall(pattern, line["Address"])
            csv_writer.writerow(postcodes)

示例数据:

Address,Name,Lat,Long,2016 Sales,Type
48  Park Avenue, LATTON, SN6 4SZ,Nikki Yellowbeard,-23.17549,36.74641,9727,AA
IV21 1TD 116  Walwyn Rd CHARLESTOWN,Jonh Doe,-10.98309,156.41854,11932,AE

3 个答案:

答案 0 :(得分:0)

最好将输入的csv文件读入数据框中,然后使用pandas.str.extract()从地址栏中提取邮政编码。

  1. 阅读csv:https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.read_csv.html
  2. 提取邮政编码:https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.Series.str.extract.html
  3. 编写csv:https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.to_csv.html

答案 1 :(得分:0)

在我看来,第一个字段地址中会出现逗号,这会造成不规则现象,但我不确定是哪种方法绕过那些错误的最佳方法,但这种表达方式是这样的:

(.*),(.*),\s*([0-9.-]+)\s*,\s*([0-9.]+)\s*,([0-9]{4,5}(?:-[0-9]{4})?)\s*,\s*([A-Z]{2})

可能是一种研究方法。


Demo


美国邮政编码通常采用以下格式:

([0-9]{5}(?:-[0-9]{4})?)

仅出于演示目的,我包括:

[0-9]{4,5}

您可以将其删除。

示例

import re

regex = r"(.*),(.*),\s*([0-9.-]+)\s*,\s*([0-9.]+)\s*,([0-9]{4,5}(?:-[0-9]{4})?)\s*,\s*([A-Z]{2})"

test_str = ("Address,Name,Lat,Long,2016 Sales,Type\n"
    "48  Park Avenue, LATTON, SN6 4SZ,Nikki Yellowbeard,-23.17549,36.74641,9727,AA\n"
    "IV21 1TD 116  Walwyn Rd CHARLESTOWN,Jonh Doe,-10.98309,156.41854,11932,AE")

matches = re.finditer(regex, test_str, re.MULTILINE)

for matchNum, match in enumerate(matches, start=1):

    print ("Match {matchNum} was found at {start}-{end}: {match}".format(matchNum = matchNum, start = match.start(), end = match.end(), match = match.group()))

    for groupNum in range(0, len(match.groups())):
        groupNum = groupNum + 1

        print ("Group {groupNum} found at {start}-{end}: {group}".format(groupNum = groupNum, start = match.start(groupNum), end = match.end(groupNum), group = match.group(groupNum)))

如果我们不验证值,则只需使用此表达式

(.*),(.*),(.*),(.*),(.*),(.*)

可能可行。

Demo

答案 2 :(得分:0)

您的样本中的CSV无效;看来您缺少在“地址”字段周围的引号。

此外,re.findall()可以返回多个结果-CSV不能真正在一个列中容纳多个值(而且当您尝试陷入混乱之中时,您现在想摆脱的困境) );通常,更好的解决方案是对数据进行规范化,以使每个字段都包含一个最小的原子数据,这些数据无法进一步分为较小的信息单元。

如果您要表示嵌套或分层数据,则可以使用JSON或XML而不是CSV作为存储格式。

通过这种方式,这是一个重构,它在每行的末尾添加一个字段,并在其中嵌入用分号分隔的邮政编码列表(如果正则表达式匹配不成功,则不添加任何代码)字段。

import csv, re

# Precompile the pattern
pattern = reccompile(r'[A-Z]{1,2}[0-9R][0-9A-Z]?[0-9][A-Z]{2}')

with open(r'Postcode/addressin.csv', 'r') as csvinput, open(r'Postcode/addressout.csv', 'w') as csvoutput:
    csv_reader = csv.DictReader(csvinput)
    csv_writer = csv.writer(csvoutput)

    outputfieldnames = ['Address', 'Name', 'Postcode']
    csv_writer.writerow(outputfieldnames)

    for line in csv_reader:
        postcodes = ';'.join(pattern.findall(line["Address"]))
        csv_writer.writerow([line["Address"], line["Name"], postcodes])