Тут розкажу про модуль 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
ми відкриваємо одночасно два файли. А далі все очевидно. Проходимось по рядках першого, запускаємо фукцію трансформації і всі результати які вона видає записуємо у рядки другого.
Filed under:
Кодерство Tagged:
Python