Divide um arquivo csv em arquivos menores quando um número inteiro é encontrado na primeira coluna

2

Eu tenho um arquivo csv com esta aparência:

1,'someval','otherval',,,,,
'','someotherval','some_otherval',,,,,
1BSD,'',,,,,
2,'val',,,,,
,,,,,,
2BSD,,,,,,
2BCD,,,,,,

Agora, quero dividir o arquivo sempre que a primeira coluna da nova linha for um valor inteiro.

Então, para a entrada csv acima & lt; Eu preciso de dois novos arquivos com conteúdo:

1,'someval','otherval',,,,,
,'someotherval','some_otherval',,,,,
1BSD,'val',,,,,

e

2,'val',,,,,
,,,,,,
2BSD,,,,,,
2BCD,,,,,,

respectivamente.

Como posso fazer isso usando Bash e / ou Python? Obrigado.

    
por kashish 04.01.2018 / 11:14

2 respostas

3

Você pode usar o utilitário csplit para dividir em uma expressão regular, por exemplo,

csplit -z file.csv '/^[0-9]\+,/' '{*}'
80
42

(as contagens indicam o número de caracteres gerados em cada arquivo - você pode suprimi-los adicionando a opção -s ).

Os arquivos de saída são nomeados xx00 , xx01 etc. por padrão - existem opções para alterar o prefixo e o sufixo, se desejar.

Ex.

$ csplit -z file.csv '/^[0-9]\+,/' '{*}'
80
42
$ head xx*
==> xx00 <==
1,'someval','otherval',,,,,
'','someotherval','some_otherval',,,,,
1BSD,'',,,,,

==> xx01 <==
2,'val',,,,,
,,,,,,
2BSD,,,,,,
2BCD,,,,,,
    
por steeldriver 04.01.2018 / 14:40
2

Eu queria ver quanto disso eu poderia fazer com sed e consegui fazer bastante disso. Podemos escrever arquivos com sed usando os comandos w e W , mas não consegui pensar em uma maneira de gravar um arquivo diferente a cada iteração de um loop sed , então tive que usar um shell loop. sed é provavelmente a ferramenta errada a ser usada para este trabalho, e provavelmente há uma maneira mais agradável de fazer isso com sed . De qualquer forma, aqui está o que eu criei:

#!/bin/bash
sed ':a;N;s/\n/\x00/; ta' input | sed -r 's/\x00([0-9]+(,|\x00|$))/\n/g' > edited
n=0
while [ -s edited ]; do 
    ((n++))
    sed -n '1p' edited > csv-"$n"
    sed -i '1d' edited
done
sed -i 'y/\x00/\n/' csv-*
rm edited

Comentários

  • substitua as novas linhas pelo caractere nulo \x00 usando um loop sed . Isso é para que possamos usar novas linhas como separadores significativos depois.

    sed ':a;N;s/\n/\x00/; ta' input
    
  • canalize o resultado e adicione novas linhas antes dos números inteiros que estavam no primeiro campo, e grave o resultado em um arquivo, edited

    | sed -r 's/\x00([0-9]+(,|\x00|$))/\n/g' > edited
    
  • inicialize uma variável para incrementar

    n=0
    
  • contanto que edited não esteja vazio, faça as coisas

    while [ -s edited ]; do
    
  • incremento n

    ((n++))
    
  • escreva a primeira linha de edited para um novo arquivo csv-$n onde $n é o valor atual de n

    sed -n '1p' edited > csv-"$n"
    
  • exclua a primeira linha de edited

    sed -i '1d' edited
    

    esse é o fim do loop, e como só temos uma linha para cada arquivo que queremos escrever, isso não é tão lento quanto processar cada linha do arquivo original em um loop, mas ainda assim é lento!

  • para cada arquivo que criamos, transformamos os caracteres nulos de volta em novas linhas

    sed -i 'y/\x00/\n/' csv-*
    
  • exclua o arquivo intermediário

    rm edited
    
por Zanna 04.01.2018 / 14:13