У меня есть три файла .csv:

File1.csv

Header1
data1;data2;data3

File2.csv

Header2
data1;data2;data3
data1;data2;data3

File3.csv

Header3
data1;data2;data3

Я хочу к ним присоединиться вот так:

Header1;     ;     ;Header2;     ;     ;Header3;     ;
data1  ;data2;data3;data1  ;data2;data3;data1  ;data2;data3
       ;     ;     ;data1  ;data2;data3;       ;     ;

Я пытался объединить файлы с помощью paste, но столбцы продолжают смешиваться. Я думаю, это происходит потому, что иногда в одном из файлов нет данных (только заголовок) или в File2.csv данных больше, чем в File1.csv. В этом случае это должно выглядеть так:

Header1;     ;     ;Header2;     ;     ;Header3;     ;
       ;     ;     ;data1  ;data2;data3;data1  ;data2;data3
       ;     ;     ;data1  ;data2;data3;       ;     ;

paste - лучший способ добиться этого?

Пс. Я могу изменить способ создания файлов .csv. Сейчас я использую точку с запятой в качестве разделителя, но это можно изменить, если это упростит задачу.

1
Matter 29 Июн 2017 в 11:53
Я бы, наверное, написал что-нибудь на Perl / Python / Ruby. Я думаю, что простая утилита командной строки, такая как paste (или join?), Не справится с вашим конкретным сценарием.
 – 
Brian Agnew
29 Июн 2017 в 12:00
Фиксировано ли количество столбцов? Если они не фиксированы, пустой файл всегда может привести только к одному столбцу. В приведенном примере у вас есть три столбца для пустого файла (файл только с заголовком)
 – 
Naks
29 Июн 2017 в 12:02
Да, количество столбцов фиксировано. Я могу изменить заголовок, чтобы за ним следовали две пустые ячейки, если это поможет (например, header ;;).
 – 
Matter
29 Июн 2017 в 13:14

1 ответ

Лучший ответ

Python :

Сценарий merge_csv.py :

import sys
with open(sys.argv[1], 'r') as f1, open(sys.argv[2], 'r') as f2, open(sys.argv[3], 'r') as f3:

    f1_lines, f2_lines, f3_lines = f1.read().splitlines(), f2.read().splitlines(), f3.read().splitlines()
    max_lines = max(len(i) for i in (f1_lines, f2_lines, f3_lines))
    fmt = '{:7s};' * 8 + '{:7s}'

    for i in range(max_lines):
        if i == 0:
            print(fmt.format(f1_lines[i],'','',f2_lines[i],'','',f3_lines[i],'',''))
        else:
            f1_args = f1_lines[i].split(';') if i < len(f1_lines) else ['', '', '']
            f2_args = f2_lines[i].split(';') if i < len(f2_lines) else ['', '', '']
            f3_args = f3_lines[i].split(';') if i < len(f3_lines) else ['', '', '']
            print(fmt.format(*(f1_args + f2_args + f3_args)))

Использование :

python merge_csv.py File1.csv File2.csv File3.csv

Выход:

Header1;       ;       ;Header2;       ;       ;Header3;       ;       
data1  ;data2  ;data3  ;data1  ;data2  ;data3  ;data1  ;data2  ;data3  
       ;       ;       ;data1  ;data2  ;data3  ;       ;       ;   
1
RomanPerekhrest 29 Июн 2017 в 18:09
Спасибо! Это работает как описано. Теперь я изменил сценарий, чтобы иметь возможность обрабатывать больше столбцов. До 7 столбцов работают нормально, но когда я пробую 8 столбцов, возникает ошибка: Traceback (most recent call last): File "merge_csv.py", line 15, in <module> print(fmt.format(*(f1_args + f2_args + f3_args))) IndexError: tuple index out of range
 – 
Matter
29 Июн 2017 в 16:52
Поделитесь своими изменениями, чтобы я мог их видеть (скажем, через pastebin.com)
 – 
RomanPerekhrest
29 Июн 2017 в 17:28
@Matter, кажется, что при разделении на ; возникают некоторые избыточные значения. Мне нужно увидеть исходные файлы. Кроме того, используйте мою сокращенную версию fmt
 – 
RomanPerekhrest
29 Июн 2017 в 18:23
Хм, с одним файлом действительно что-то не так. Я попробовал еще раз с некоторыми другими файлами, и теперь он работает. Также с 8 столбцами. Однако сокращенная версия fmt, похоже, не работает. Я вижу только два сливаемых файла, причем частично. Ваш исходный сценарий работает нормально. Я проведу еще несколько тестов на выходных. Спасибо еще раз.
 – 
Matter
29 Июн 2017 в 19:49
@Matter, обратите внимание: в случае файла с 8 столбцами он должен быть fmt = '{:7s};' * 23 + '{:7s}' (проверено на Python 3.5)
 – 
RomanPerekhrest
29 Июн 2017 в 19:53