Como mesclar as duas primeiras linhas de um csv coluna por coluna?

4

Eu tenho um arquivo excel que converti para csv. Quando convertido, parece com o exemplo a seguir (Observe que há mais de 100 colunas no csv. Esta é uma versão reduzida):

,Product,"  ",Citty,"   ",Price
,Name," ",Location,"    ",Per Unit
,banana,"   ",CA,"  ",5.7
,apple,"    ",FL,"  ",2.3

Eu preciso escrever um script que leve o primeiro & segunda linha e "mesclá-los" juntos com base na posição de vírgula:

,Product Name," ""  ",Citty Location,"  ""  ",Price Per Unit
,banana,"   ",CA,"  ",5.7
,apple,"    ",FL,"  ",2.3

Eu olhei para outras questões aqui e estouro de pilha, mas as respostas não parecem pertencer a esta estranha situação de coluna por coluna para apenas as 2 primeiras linhas do arquivo.

Como uma tarefa adicional não relacionada, eu também gostaria de me livrar das colunas vazias no csv e corrigir o erro de ortografia para que fique assim:

Product Name,City Location,Price Per Unit
banana,CA,5.7
apple,FL,2.3

(O csv atualmente possui uma aba entre aspas entre cada coluna real de dados, exceto a primeira coluna, que está vazia, seguida de uma vírgula).

Eu estarei recebendo o csv com o erro de ortografia várias vezes, então gostaria de corrigir o erro no script programaticamente. Observe também que as colunas podem não estar sempre na ordem mostrada acima, portanto, preciso verificar dinamicamente o nome de cada coluna para o erro durante o script.

    
por takanuva15 06.08.2018 / 00:00

3 respostas

5

Tente isso

$ awk -F, 'NR<2{split(gensub(/Citty/,"City","g",$0),a,FS)}NR==2{for(b=2;b<=NF;b+=2){c=c a[b]" "$b","}print gensub(/,$/,"",1,c)}NR>2{print gensub(/(^,|" *",)/,"","g",$0)}' inp
Product Name,City Location,Price Per Unit
banana,CA,5.7
apple,FL,2.3
$

O mesmo código é mais legível se dividido em algumas linhas:

$ awk -F, '
> NR<2{split(gensub(/Citty/,"City","g",$0),a,FS)}
> NR==2{for(b=2;b<=NF;b+=2){c=c a[b]" "$b","}print gensub(/,$/,"",1,c)}
> NR>2{print gensub(/(^,|" *",)/,"","g",$0)}' inp
Product Name,City Location,Price Per Unit
banana,CA,5.7
apple,FL,2.3
$

Se 1a linha, divida a linha em elementos de matriz dentro de um. Corrigir o erro de digitação Citty- > City.

Se a segunda linha, começando com a segunda coluna, imprima a coluna correspondente da primeira linha junto com essa coluna. Repita para cada coluna, indo em incrementos de 2 colunas. Remova o , .

Após a segunda linha, substitua qualquer% principal, ou qualquer "<spaces>", por uma string vazia e, em seguida, imprima o resultado.

Testado ok no GNU Awk 4.0.2

Experimente online!

    
por 06.08.2018 / 00:14
4

Usando Perl, com Text :: CSV e MoreUtils:

perl -MText::CSV -MList::MoreUtils=pairwise -lne '
  BEGIN { $p = Text::CSV->new(); } 
  @f = $p->fields() if $p->parse($_);
  @hdr = map { s/Citty/City/ ; $_ } @f if $. == 1;
  @f = pairwise { $a . " " . $b } @hdr, @f if $. == 2;
  print join ",", grep { /\w/ } @f if $. > 1;
' file.csv
Product Name,City Location,Price Per Unit
banana,CA,5.7
apple,FL,2.3

O grep omite campos que não contêm pelo menos um caractere de palavra.

Com perl > = 5.14.0 você pode simplificar a substituição para map s/Citty/City/r @f usando a substituição não-destrutiva modificador.

    
por 06.08.2018 / 02:08
3

Tente

    awk -F, '
            {gsub (/,*"[    ]*",*/, ",")
             sub (/^,/, "")
             sub (/Citty/, "City")
            }

    NR == 1 {n = split ($0, T)
             next
            }
    NR == 2 {for (;n; n--) $n = T[n] " " $n
            }

    1
    ' OFS=, file
Product Name,City Location,Price Per Unit
banana,CA,5.7
apple,FL,2.3
    
por 06.08.2018 / 00:36