web-dev-qa-db-fra.com

Fractionner un fichier csv en fichiers plus petits lorsqu'un entier trouvé dans la première colonne

J'ai un fichier csv qui ressemble à ceci:

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

Maintenant, je veux diviser le fichier chaque fois que la première colonne de la nouvelle ligne est un entier.

Donc, pour l’entrée csv ci-dessus <je dois obtenir 2 nouveaux fichiers avec le contenu:

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

et

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

respectivement.

Comment puis-je accomplir cela en utilisant Bash et/ou Python? Merci.

2
kashish

Vous pouvez utiliser l'utilitaire csplit pour fractionner une expression régulière, par exemple.

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

(les comptes indiquent le nombre de caractères sortis dans chaque fichier - vous pouvez les supprimer en ajoutant l'option -s).

Les fichiers de sortie sont nommés xx00, xx01 etc. par défaut - il existe des options pour modifier le préfixe et le suffixe si vous le souhaitez.

Ex.

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

==> xx01 <==
2,'val',,,,,
,,,,,,
2BSD,,,,,,
2BCD,,,,,,
3
steeldriver

Je voulais voir tout ce que je pouvais faire avec sed et j'ai réussi à en faire beaucoup. Nous pouvons écrire des fichiers avec sed en utilisant les commandes w et W, mais je ne pouvais pas trouver un moyen d'écrire un fichier différent à chaque itération d'une boucle sed , j'ai donc dû utiliser une boucle Shell. sed est probablement le mauvais outil à utiliser pour ce travail, et il existe probablement un moyen plus agréable de le faire avec sed. Quoi qu'il en soit, voici ce que je suis venu avec:

#!/bin/bash
sed ':a;N;s/\n/\x00/; ta' input | sed -r 's/\x00([0-9]+(,|\x00|$))/\n\1/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

Commentaires

  • remplacez les nouvelles lignes par le caractère nul \x00 en utilisant une boucle sed. Ceci afin que nous puissions utiliser les nouvelles lignes comme séparateurs significatifs ultérieurement.

    sed ':a;N;s/\n/\x00/; ta' input
    
  • dirige le résultat et ajoute des nouvelles lignes avant les entiers qui étaient dans le premier champ, et écrit le résultat dans un fichier, edited

    | sed -r 's/\x00([0-9]+(,|\x00|$))/\n\1/g' > edited
    
  • initialiser une variable à incrémenter

    n=0
    
  • tant que edited n'est pas vide, fais les choses

    while [ -s edited ]; do
    
  • incrémenter n

    ((n++))
    
  • écrire la première ligne de edited dans un nouveau fichier csv-$n$n est la valeur actuelle de n

    sed -n '1p' edited > csv-"$n"
    
  • supprimer la première ligne de edited

    sed -i '1d' edited
    

    c'est la fin de la boucle, et comme nous avons seulement une ligne pour chaque fichier que nous voulons écrire, ce n'est pas aussi lent que de traiter chaque ligne du fichier d'origine dans une boucle, mais quand même, c'est lent!

  • pour chaque fichier créé, reconvertissez les caractères nuls en nouvelles lignes

    sed -i 'y/\x00/\n/' csv-*
    
  • supprimer le fichier intermédiaire

    rm edited
    
2
Zanna