web-dev-qa-db-fra.com

Créer un fichier csv à partir d'un fichier texte incohérent

J'ai des enregistrements peu structurés dans un fichier constitué de 3 ou 4 lignes de texte séparées (le plus souvent) par une ligne vierge. Tous les enregistrements ne comportent pas de séparateur de ligne vide, mais la dernière ligne de chacun commence par le mot "Ajouté". Je voudrais produire un fichier csv avec chaque enregistrement sur une ligne précédée de son numéro de ligne. Jusqu'à présent, je n'ai pu produire qu'une concaténation de tous les enregistrements séparés par un nombre arbitraire d'espaces et une virgule redondante.

Logiquement, j'essaie d'atteindre les objectifs suivants:

Lire la ligne, si la ligne commence 'Ajoutée' conserver la nouvelle ligne à la fin
sinon remplacer 'newline' par ','
ou si la ligne est vide, supprimez-le
fin si

Échantillon de données:

Peter Green  
Space Monkey at Area 51  
Joined  
Added by SF 3 weeks ago  
Will Rossiter  
Joined  
Added by SF 3 weeks ago

Dean Matthews  
Guitarist at Blues  
Joined  
Added by SF 3 weeks ago  
Hobbit Mak  
Farnborough, United Kingdom  
Joined  
Added by SF 3 weeks ago  

Keneth W Moorfield  
THE STOREMAN  
Joined  
Added by SF 3 weeks ago  
Mick Georgious  
Software Engineer  
Joined  
Added by SF 3 weeks ago
4
SeniorMoments

Essayer:

awk '/./{ printf "%s%s", $0, (/Added/?"\n":",") }' data

En utilisant vos exemples de données d'entrée:

$ awk '/./{printf "%s%s",$0,(/Added/?"\n":",")}' data
Peter Green,Space Monkey at Area 51,Joined,Added by SF 3 weeks ago
Will Rossiter,Joined,Added by SF 3 weeks ago
Dean Matthews,Guitarist at Blues,Joined,Added by SF 3 weeks ago
Hobbit Mak,Farnborough, United Kingdom,Joined,Added by SF 3 weeks ago
Keneth W Moorfield,THE STOREMAN,Joined,Added by SF 3 weeks ago
Mick Georgious,Software Engineer,Joined,Added by SF 3 weeks ago

Comment ça fonctionne:

  • /./{...}

    Cela exécute les commandes entre accolades uniquement si la ligne contient un caractère. En d'autres termes, cela ignore les lignes vides.

  • printf "%s%s",$0,(/Added/?"\n":",")

    Ceci affiche la ligne, notée $0, suivie d’une virgule ou d’une nouvelle ligne selon que la ligne correspond à la regex Added.

5
John1024

Voici une solution possible sed (avec awk, faites la numérotation des lignes):

$ sed -n -e :a -e '$!{/^$/!N}; /,Added/ {P;D}; s/\n/,/; ta' data | awk '{print NR","$0}'
1,Peter Green,Space Monkey at Area 51,Joined,Added by SF 3 weeks ago
2,Will Rossiter,Joined,Added by SF 3 weeks ago
3,Dean Matthews,Guitarist at Blues,Joined,Added by SF 3 weeks ago
4,Hobbit Mak,Farnborough, United Kingdom,Joined,Added by SF 3 weeks ago
5,Keneth W Moorfield,THE STOREMAN,Joined,Added by SF 3 weeks ago
6,Mick Georgious,Software Engineer,Joined,Added by SF 3 weeks ago 

Fondamentalement, nous continuons simplement à ajouter des lignes d’entrée non vides et à remplacer leurs nouvelles lignes par des virgules, sauf que nous vérifions à chaque itération si nous avons un enregistrement complet et, si nous en avons, nous le cracherions i.e.

  • définir une étiquette de programme :a
  • sinon à la fin du fichier $! puis ajoutez des lignes non vides à l'espace-modèle {/^$/!N}
  • si nous sommes à la fin d'un enregistrement /,Added/, imprimez-le P et supprimez-le D de l'espace de répétition
  • remplacez la virgule par newline s/,/\n/ et revenez à a en cas de succès
3
steeldriver

FWIW, voici une option Perl:

$ Perl -lne '
    Push @rec, $_ unless /^$/; if (/^Added/) {print join ",", ++$n, @rec; undef @rec;}
' data
1,Peter Green,Space Monkey at Area 51,Joined,Added by SF 3 weeks ago
2,Will Rossiter,Joined,Added by SF 3 weeks ago
3,Dean Matthews,Guitarist at Blues,Joined,Added by SF 3 weeks ago
4,Hobbit Mak,Farnborough, United Kingdom,Joined,Added by SF 3 weeks ago
5,Keneth W Moorfield,THE STOREMAN,Joined,Added by SF 3 weeks ago
6,Mick Georgious,Software Engineer,Joined,Added by SF 3 weeks ago 
2
steeldriver