Разобрать одну таблицу из CSV с несколькими таблицами с названием модуль Python CSV-файл


Я ищу для разбора CSV-файлов, содержащих несколько таблиц с помощью Python 3-х csv модуль.

Эти сложные они не в отличие от игрушки, например ниже. Моя цель-сделать идиома для выбора любой таблице, используя известную строку заголовка.

Комплекс CSV-файл toy.csv:

lists, fruits, books, forks, rope, gum
4, 2, 3, 0, 2, 2

Manhattan Produce Market
id, fruit, color
1, orange, orange
2, apple, red

Books
id, book, pages
1, Webster’s Dictionary, 1000
2, Tony the Towtruck, 20
3, The Twelfth Night, 144

Rope
id, rope, length, diameter, color
1, hemp, 12-feet, .5, green
2, sisal, 50-feet, .125, brown

Kings County Candy
id, flavor, color, big-league
1, grape, purple, yes
2, mega mango, yellow-orange, no

Каждой таблице предшествует заголовок (за исключением таблицы фигня на старте). Я сохраняю предыдущего ряда, и, когда я соответствовать правильный заголовок таблицы, я добавить заголовок нового столбца.

import csv, re
header = [] #doesn't need to be list, but I'm thinking ahead
table = [] 

with open('toy.csv', 'r') as blob:
    reader = csv.reader(blob)
    curr = reader.__next__()
    while True: 
        prev = curr
        try:
            curr = reader.__next__()
        except StopIteration:
            break 
        if not ['id', ' book', ' pages'] == curr: 
            continue
        else:             
            header.append(prev) 
            table.append(['title'] + curr)            
            while True: 
                try:
                    curr = reader.__next__()
                    if curr == []:
                        break
                    else:
                        table.append(header[0] + curr)
                except StopIteration:
                    break

Первая часть-сделать идиоматическое выражение, которым я могу просто повторить для каждой таблицы, я хочу, чтобы извлечь. Позже я объединить таблицы в одну супер-таблицу заполнять Нанс, где заголовки таблицы не совпадают.

[['title', 'id', ' book', ' pages'],
 ['Books', '1', ' Webster’s Dictionary', ' 1000'],
 ['Books', '2', ' Tony the Towtruck', ' 20'],
 ['Books', '3', ' The Twelfth Night', ' 144']]

Кодекс основан на это переполнение стека пост.

С удовольствием выслушаю ваши предложения, чтобы сделать код более компактным, устойчивым и пригодным для моих целей.



1698
7
задан 18 февраля 2018 в 01:02 Источник Поделиться
Комментарии
2 ответа

В общем этот код выглядит очень красиво и, кажется, следовать принципам стиля. Я нашел ваш код легко следовать. Вы просили:


... предложения, чтобы сделать код более компактным, устойчивым и пригодным для моих целей.

Я начну с пары очков для компактных и идиоматические, а затем добавить что-то немного более широкую картину.

Нужна только одна остановка итерации:

Ваш основной цикл использует эти два построения:

try:
....
except StopIteration:
break

Но чистым результатом этих одинаков, а внутренний можно было бы просто убрать.

Dunders Acccessing обычно uneeded:

В нескольких местах ваш код имеет что-то вроде:

curr = reader.__next__()

Идиоматические способ сделать это:

curr = next(reader)

В __next__ (Дандер рядом) способ есть, так как объект издает свой интерфейс next(). И в то время как вы можете получить доступ к этому, вы, пожалуй, не стоит.

Кроме того весь ваш цикл, используя next(). Я полагаю, что скорее всего это означает, что ваши структуры итерации может использовать некоторые доработки. Ищете более естественный элемент итерации может позволить код должен быть упрощен.

Использовать природное перерывы:

Сейчас что-то немного более существенное.

Структура данных имеет естественный перерыв между записями как пустую строку. Отметив наличие этой пустой строки в анализе логики, в логике анализа можно сделать немного проще. В вашем коде, вы должны иметь:

prev = curr

Которая необходима, чтобы добраться до задней линии, чтобы найти название категории. Но в ту же категорию, как уже отмечалось, через пустую строку перед.

Я начал переделывать свой код в качестве примера того, как воспользоваться этим пустую строку, и нашел его так же легко читать на весь файл. Пример ниже не сохраняет логику ищу главами категории:

 ['id', ' book', ' pages']

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

Код Переделывать Парсинг:

def read_my_csv(filename):
category = None
header = None
record_data = {}
table = []

def make_record():
return [dict(zip(header, x)) for x in table]

with open(filename, 'rU') as csv_data:
reader = csv.reader(csv_data)

for row in reader:
if not row:
if category:
record_data[category] = make_record()
table = []
category = next(reader)[0]
header = tuple(x.strip() for x in next(reader))
else:
table.append([x.strip() for x in row])

if category:
record_data[category] = make_record()
return record_data

Тестовый Код:

import csv
data = read_my_csv('csvfile.csv')
for item in data.items():
print(item[0])
for records in item[1]:
for record in records.items():
print(' {}'.format(record))
print()

Результаты переформулировала:

Manhattan Produce Market
('id', '1')
('fruit', 'orange')
('color', 'orange')

('id', '2')
('fruit', 'apple')
('color', 'red')

Books
('id', '1')
('book', 'Webster’s Dictionary')
('pages', '1000')

('id', '2')
('book', 'Tony the Towtruck')
('pages', '20')

('id', '3')
('book', 'The Twelfth Night')
('pages', '144')

Rope
('id', '1')
('rope', 'hemp')
('length', '12-feet')
('diameter', '.5')
('color', 'green')

('id', '2')
('rope', 'sisal')
('length', '50-feet')
('diameter', '.125')
('color', 'brown')

Kings County Candy
('id', '1')
('flavor', 'grape')
('color', 'purple')
('bigleague', 'yes')

('id', '2')
('flavor', 'mega mango')
('color', 'yellow-orange')
('bigleague', 'no')

8
ответ дан 18 февраля 2018 в 05:02 Источник Поделиться

Итерации

Чтобы получить следующий элемент из итератора, вы должны позвонить next(<em>iter</em>). В <em>iter</em>.__next__() способ реализуется итератор, но это не то, что вы должны назвать его.

Из-за своей prev = curr и глубокой вложенности while True, try … except StopIterationваши итерации топорно. Вызов, который вы имеете разбиение входных данных на разделы (разделенных пустой строкой). Для этого, я рекомендую itertools.takewhile().

КШМ разбора

Ваш ввод не традиционный КШМ. Скорее, поля разделяются запятой с последующим неприятность пространства. Чтобы читать этот формат, вы должны инстанцировать csv.reader С skipinitialspace=True вариант.

Нежели искать строфы с заголовками 'id', 'book'и 'pages'Я предлагаю парсинг всех строф, и используя только то, что 'Books' в качестве заголовка.

Предлагаемое решение

import csv
from itertools import takewhile

with open('toy.csv') as f:
csv_reader = csv.reader(f, skipinitialspace=True)
tables = {}
try:
while True:
title = next(f).rstrip()
stanza = takewhile(lambda row: row, csv_reader)
tables[title] = [['title'] + next(stanza)] + \
[[title] + row for row in stanza]
except StopIteration:
pass # EOF while reading title or header row

print(tables['Books'])

2
ответ дан 19 февраля 2018 в 06:02 Источник Поделиться