Вывести re.findall () в CSV в дополнение ко всем входным данным - PullRequest
1 голос
/ 30 июня 2019

Я пытаюсь сохранить результаты поиска регулярных выражений .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 голосов
/ 30 июня 2019

Мне кажется, что в первых полях адреса есть запятые, которые могут создавать неровности, и я не уверен, что может быть лучшим способом их обойти, но это выражение:

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

может быть подходом для изучения.


Демо


Почтовые индексы США обычно имеют следующие форматы:

([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)))

Если бы мы не проверяли значения, то просто это выражение

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

может сработать.

Демо

0 голосов
/ 01 июля 2019

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])
0 голосов
/ 30 июня 2019

вам, вероятно, лучше, прочитав входной CSV-файл во фрейм данных, а затем используйте pandas.str.extract (), чтобы извлечь почтовый индекс из столбца адреса.

  1. read 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...