Блоґ одного кібера

Історія хвороби контуженого інформаційним вибухом

Фреймворк фільтра TSV (CSV)

leave a comment »

Тут розкажу про модуль csv в Python, та як змусити його реагувати на кодування файлів.

TSV (значення розділені табуляцією) – це формат таблиці, яка зберігається в звичайному текстовому файлі і в якій кожен рядок – це рядок тексту, а стовпці розділяються символом табуляції. Його вміють відкривати всілякі програмки електронних таблиць, але перевага ще й в тому що його можна прочитати за допомогою звичайнісінького cat. Для прикладу табличка з групами крові (дані не перевірені, якщо ви сюди за ними, то краще спитайте лікаря):

bunyk@xubuntyk:~/tsv_filter_test$ cat blood.tsv 
Тип	Можливий донор для
A+	A+, AB+
O+	O+, A+, B+, AB+
B+	B+, AB+
AB+	AB+
A-	A+, A-, AB+, AB-
O-	A+, O+, B+, AB+, A-, O-, B-, AB-
B-	B+, B-, AB+, AB-
AB-	AB+, AB-


Давайте напишемо програму, яка візьме цю табличку, і перетворить її на табличку з парами дозволених переливань:

from csv_wrapper import transform_tsv # про це трохи далі 

def main():
    transform_tsv('blood.tsv', 'blood_pairs.tsv', transformation)

def transformation(row, num):
    if num == 0: # перший рядок - заголовок
        yield row # не чіпаємо
        return
    for recipient in row[1].split(', '): # пробігаємо по списку реципієнтів в другій колонці
        yield (row[0], recipient) # і віддаємо для кожної пари донор-реципієнт новий рядок

if __name__ == '__main__':
    main()

Отримуємо файл що починається так:

bunyk@xubuntyk:~/tsv_filter_test$ head blood_pairs.tsv 
Тип	Можливий донор для
A+	A+
A+	AB+
O+	O+
O+	A+
O+	B+
O+	AB+
B+	B+
B+	AB+
AB+	AB+

Тепер про те як працює transform_tsw. Вона використовує стандартну бібліотеку, але проблема зі стандартним модулем csv в тому що в python2 він дуже погано дружить з кодуваннями, і вимагає передавати йому байти, бо, бачте, з закінченнями рядків він сам хоче розібратись… Є ще модуль unicodecsv, який вирішує проблему з Python2, але в Python3 csv вже нормально спілкується Юнікодом, а open приймає кодування, тому там він не такий корисний.

Як варіант, ми використаємо адаптер описаний в книжці Porting to Python3. Тут його наводити не будемо, бо довгий (я його додав в бібліотеку butils), а просто розглянемо функцію transform_tsv, бо цікава:

def transform_tsv(src, dst, transformation, encoding='utf-8'):
    with UnicodeReader(src, encoding=encoding, delimiter='\t') as reader, \
        UnicodeWriter(dst, encoding=encoding, delimiter='\t') as writer:
        for i, src_row in enumerate(reader):
            for dst_row in transformation(src_row, i):
                writer.writerow(dst_row)

Тут за допомогою with ми відкриваємо одночасно два файли. А далі все очевидно. Проходимось по рядках першого, запускаємо фукцію трансформації і всі результати які вона видає записуємо у рядки другого.

Advertisements

Written by bunyk

Квітень 12, 2014 at 09:41

Оприлюднено в Кодерство

Tagged with

Залишити відповідь

Заповніть поля нижче або авторизуйтесь клікнувши по іконці

Лого WordPress.com

Ви коментуєте, використовуючи свій обліковий запис WordPress.com. Log Out / Змінити )

Twitter picture

Ви коментуєте, використовуючи свій обліковий запис Twitter. Log Out / Змінити )

Facebook photo

Ви коментуєте, використовуючи свій обліковий запис Facebook. Log Out / Змінити )

Google+ photo

Ви коментуєте, використовуючи свій обліковий запис Google+. Log Out / Змінити )

З’єднання з %s

%d блогерам подобається це: