除了所有输入数据外,还输出一个 re.findall() 到 CSV
Output a re.findall() to CSV in addition to all input data
我正在尝试将正则表达式 .findall() 搜索的结果保存到 csv 中,但在将结果附加到输出文件时遇到困难。
因为我对 Python 还是很陌生,所以我试图将这个问题限制在仅使用 csv 和 re 库 - 但如果有更简单的方法(即在 pandas 中)这也将有助于了解。
如何将输入 CSV 的全部内容复制到输出 CSV 并将邮政编码/找到的正则表达式添加到找到它的行?
是否有任何明显的错误检查形式或其他我遗漏的东西?
是否有更好的方法将输入 CSV 的 header 自动添加到输出 CSV 而无需明确指定它们?
是否可以使用 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
您最好将输入的 csv 文件读取到数据框中,然后使用 pandas.str.extract() 从地址栏中提取 post 代码。
在我看来,第一个字段地址中的逗号会造成不规则,我不太确定绕过这些逗号的最佳方法是什么,但是这个表达式:
(.*),(.*),\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
您样本中的 CSV 无效;看起来您在地址字段周围缺少引号。
此外,re.findall()
可以 return 多个结果 - CSV 不能真正在一列中容纳多个值(当你尝试时,你会陷入混乱试图摆脱现在);一般来说,一个更好的解决方案是规范化您的数据,以便每个字段都包含最小的原子数据,这些数据不能进一步划分为更小的信息单元。
如果您尝试表示嵌套或分层数据,可以查看 JSON 或 XML 而不是 CSV 作为您的存储格式。
除此之外,这里是一个重构,它在每一行的末尾添加一个字段,并嵌入一个 semicolon-separated 列表 post 代码(或者什么都没有,如果正则表达式匹配不成功)到该字段。
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])
我正在尝试将正则表达式 .findall() 搜索的结果保存到 csv 中,但在将结果附加到输出文件时遇到困难。
因为我对 Python 还是很陌生,所以我试图将这个问题限制在仅使用 csv 和 re 库 - 但如果有更简单的方法(即在 pandas 中)这也将有助于了解。
如何将输入 CSV 的全部内容复制到输出 CSV 并将邮政编码/找到的正则表达式添加到找到它的行?
是否有任何明显的错误检查形式或其他我遗漏的东西?
是否有更好的方法将输入 CSV 的 header 自动添加到输出 CSV 而无需明确指定它们?
是否可以使用 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
您最好将输入的 csv 文件读取到数据框中,然后使用 pandas.str.extract() 从地址栏中提取 post 代码。
在我看来,第一个字段地址中的逗号会造成不规则,我不太确定绕过这些逗号的最佳方法是什么,但是这个表达式:
(.*),(.*),\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
您样本中的 CSV 无效;看起来您在地址字段周围缺少引号。
此外,re.findall()
可以 return 多个结果 - CSV 不能真正在一列中容纳多个值(当你尝试时,你会陷入混乱试图摆脱现在);一般来说,一个更好的解决方案是规范化您的数据,以便每个字段都包含最小的原子数据,这些数据不能进一步划分为更小的信息单元。
如果您尝试表示嵌套或分层数据,可以查看 JSON 或 XML 而不是 CSV 作为您的存储格式。
除此之外,这里是一个重构,它在每一行的末尾添加一个字段,并嵌入一个 semicolon-separated 列表 post 代码(或者什么都没有,如果正则表达式匹配不成功)到该字段。
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])