Scripting para dividir uma única linha CSV em vários

2

Eu preciso de um script que possa pegar um arquivo CSV com uma coluna de atributos delimitados por ponto-e-vírgula e dividi-lo em várias linhas para normalizar esse atributo de valores múltiplos? Aqui está o cenário:

Atual:

John,Doe,"Foo1;Bar1;Foo2;Bar2"

Alvo:

John,Doe,Foo1 
John,Doe,Bar1 
John,Doe,Foo2 
John,Doe,Bar2

Editar (Respondido) : A resposta da Avinash foi fácil, suficiente e, como observei nos comentários, exigiu apenas algumas alterações. A atualização a seguir (peça desculpas antecipadas pelo meu roteiro insatisfatório), atualizei a resposta da Avinash para trabalhar com o Python 2.4 e acomodar o número N de colunas. Aviso de isenção de responsabilidade: isso só funcionará se a última coluna for de valor múltiplo, mas alguns loops e se / elses puderem resolver isso se alguém quiser.

#!/usr/bin/python3
import csv
import sys
fil = sys.argv[1]
f = open(fil)
try:
    reader = csv.reader(f)
    for i in reader:
        l = []
        for x in i:
            if ';'  in x:
                m = x.split(';')
                l.append(m)
                splitCol = len(l)-1
            else:
                l.append(x)
        for j in l[splitCol]:
            strng = ''
            for colCount in range(len(l)):
                if colCount != splitCol and colCount == 0:
                     strng = strng+''.join(i[colCount])
                elif colCount != splitCol and colCount != 0:
                     strng = strng+','+''.join(i[colCount])
                elif colCount == splitCol and colCount == 0:
                     strng = strng+j
                else:
                     strng = strng+','+j
            print(strng)
finally:
    f.close()
    
por ps2005 11.02.2015 / 03:15

6 respostas

2

Através do python3.

#!/usr/bin/python3
import csv
import sys
fil = sys.argv[1]
with open(fil) as f:
    reader = csv.reader(f)
    for i in reader:
        l = []
        for x in i:
            if ';'  in x:
                m = x.split(';')
                l.append(m)
            else:
                l.append(x)

        for j in l[2]:
            print(l[0]+','+l[1]+','+j)

Salve o script acima em um arquivo e nomeie-o como script.py . Execute este script por

python3 script.py inputfile
    
por 11.02.2015 / 04:31
2

Se você deseja algo rápido e não sabe que seus dados têm exatamente três campos, como mostrado, talvez algo como

awk -F, -vOFS=, '{split(substr($3,2,length($3)-2),a,";"); for (i in a) print $1,$2,a[i];}' file.csv
    
por 11.02.2015 / 04:40
1

Mais um pythonic form

#!/usr/bin/env python3

string= 'John,Doe,"Foo1;Bar1;Foo2;Bar2"'
result = [ string.split('"')[0] + x for x in string.split('"')[1].split(";")]
for i in result:
    print(i)

Resultado:

$ ./test.py 
John,Doe,Foo1
John,Doe,Bar1
John,Doe,Foo2
John,Doe,Bar2
    
por 11.02.2015 / 06:56
0

Aqui estão alguns sed que você pode usar para fazer isso:

sed 'H; 1h; g; x; s/^\n//
/^\([^"]*\)"\([^"]*".*\)/!  d
        s///; x; s///; :t
/\n\{0,1\}\([^;,"]*\)[";]\(.*\)/{ H
        s///; x; s///p
        s/\(.*,\).*//; x
        /^[^,"]*,\(.*\)/!bt
};s///;x;s///;G;x;s///;x;D

Eu sei - parece longo. Mas - enquanto os buffers de memória de sed não cederem sob pressão - isto deve lidar com qualquer tipo de texto dentro de seus campos, dado alguns (como eu penso) advertências realistas:

  1. As porções de " citadas não podem conter citações de escape
  2. O último campo deve ser um campo com " e aspas " devem ser pareadas de maneira uniforme.
  3. Os campos delimitados por ; não podem conter vírgulas, aspas ou ; semicolons
  4. Deve haver pelo menos um campo separado por vírgula liderando cada porção " cotada.

Veja um exemplo:

sed ... <<\INPUT
John,Doe,"Foo1;Ba

r1;Foo2;Bar2",Jane,Doe,"Foo3;Bar3;Foo4;Bar4",All,Work,And,

No,Play,Makes,Jack,"A Superhero;
A

Very

Dull

Boy"
INPUT

Se você preencher o ... acima com o script sed na parte superior desta resposta, deverá obter a seguinte saída:

John,Doe,Foo1
John,Doe,Ba

r1
John,Doe,Foo2
John,Doe,Bar2
Jane,Doe,Foo3
Jane,Doe,Bar3
Jane,Doe,Foo4
Jane,Doe,Bar4
All,Work,And,

No,Play,Makes,Jack,A Superhero
All,Work,And,

No,Play,Makes,Jack,
A

Very

Dull

Boy
    
por 11.02.2015 / 09:45
0
#!/usr/bin/perl -n

if(/(.*?,)"(.*?;*?)"(.*)/){ my ($a,$b,$c)=($1,$2,$3) ;
       for( split(/\s*;\s*/,$b )){
          print "$a$_$c\n"
       }
}
    
por 12.02.2015 / 00:42
0

Aqui está outra solução usando o Python 2:

#!/usr/bin/env python2
input_string = 'John,Doe,"Foo1;Bar1;Foo2;Bar2"'
input_list = input_string.split('"')
common_input = input_list[0]
changed_input = input_list[1].split(';')
for i in changed_input:
    print common_input + i

Saída:

John,Doe,Foo1
John,Doe,Bar1
John,Doe,Foo2
John,Doe,Bar2
    
por 12.02.2015 / 04:46