Traitement fichier CSV avec "sed"

Résolu/Fermé
yann747 Messages postés 128 Date d'inscription mardi 25 octobre 2011 Statut Membre Dernière intervention 13 octobre 2021 - 2 janv. 2012 à 21:20
 yann747 - 4 janv. 2012 à 15:52
Bonjour à tous,
je souhaite traiter un fichier CSV que je souhaite inserer dans un base de données mysql.
il se présente sous la forme suivante:

Fichier CSV
"Auteur";"Filmographie" \retour ligne ... ainsi de suite...


Jusque là tout va bien, mais le problème que je rencontre
est que dans un même champs il y a plusieurs infos et en nombre variable...
Explication:

Structure du champs Filmographie:

[Titre du film]||[annee de tournage||[Type]
séparateur dans le champs: || (en nombre fixe)
Séparateur occurrence d'un item: ## (en nombre variable)

Exemple:
"Martin Scorsese";"Mad Max||1979||Action||Raging Bull||1980##1981||Drame||Cannonball||1975||Action##Comédie##Drame" \retour ligne

J'aurais aimé avoir ça sous une forme plus simple à traiter pour moi, du genre:

"Martin Scorsese";"Mad Max";"1979";"Action" \retour ligne
"Martin Scorsese";"Raging Bull";"1980-1981";"Drame" \retour ligne
"Martin Scorsese";"Cannonball";"1975";"Action-Comédie-Drame" \retour ligne

Pourquoi le Forum Linux?
Je pensais à la commande sed, qui m'a déjà rendu de bons services mais que je ne maitrise pas.
Merci d'avance de vos propositions.

8 réponses

Utilisateur anonyme
3 janv. 2012 à 12:11
salut,

J'utiliserais plutôt awk
awk -F';' '{
   gsub("\"","")
   gsub("##","-")
   n = split($2,a,"\\|\\|")
   for(i=1; i<=n; i++){
      if(i%3){
         f = (f ? f";\""a[i]"\"" : "\""a[i]"\"")
      }else{
         print "\""$1"\";"f";\""a[i]"\""; f = ""
      }
   }
}' filmografictive
parce que ça va être pénible de retenir le premier champ, et de le rajouter quand il faut en sed.
1
zipe31 Messages postés 36402 Date d'inscription dimanche 7 novembre 2010 Statut Contributeur Dernière intervention 27 janvier 2021 6 407
Modifié par zipe31 le 3/01/2012 à 14:33
Salut,

$ cat film.txt  
"Martin Scorsese";"Mad Max||1979||Action||Raging Bull||1980##1981||Drame||Cannonball||1975||Action##Comédie##Drame" 

$ cat format.sed  
s/;/\n/4 
s/\([^;]*;\)\(.*\n\)\(.*\)/\1\2\1\3/ 
P 
D 

$ cat pre-format.sed  
s/||/";"/g 
s/##/-/g 

$ sed -f format.sed < <(sed -f pre-format.sed film.txt) 
"Martin Scorsese";"Mad Max";"1979";"Action" 
"Martin Scorsese";"Raging Bull";"1980-1981";"Drame" 
"Martin Scorsese";"Cannonball";"1975";"Action-Comédie-Drame" 

$

;-))

Zen my nuggets ;-)
Faites un geste pour l'environnement, fermez vos fenêtres et adoptez un manchot.
1
C'est presque ça :-)

-quand le champ que je veux supprimer (année du film) comporte un ##
ça donne un retour ligne prématuré... et le champs (année du film apparaît encore)...

-les deux premiers champs fixes "Nationalité" et "Realisateur"
ne reviennent pas systématiquement en chaque début de ligne

en tout cas merci beaucoup, je continue d'essayer de mon côté, sur bien meilleures bases :-)
1
zipe31 Messages postés 36402 Date d'inscription dimanche 7 novembre 2010 Statut Contributeur Dernière intervention 27 janvier 2021 6 407
3 janv. 2012 à 19:09
Euh... par rapport à ton exemple je ne peux pas faire mieux ;-((

Ou il y a des trucs que je n'ai pas pigé ;-\


-quand le champ que je veux supprimer (année du film) comporte un ##
ça donne un retour ligne prématuré... et le champs (année du film apparaît encore)...

Pas chez moi ;-\

-les deux premiers champs fixes "Nationalité" et "Realisateur"
ne reviennent pas systématiquement en chaque début de ligne

Dans mon exemple si ;-\

Forcément si ton fichier original est différent de l'exemple donné, le risque de bugs n'est pas exclu ;-(
0
effectivement ça marche bien pour l'exemple donné... je regarde la subtlité oubliée...
0
s/||/";"/g
s/ ## /"\n"/g 


ça je comprends bien, ça marche... remplacer les double pipe par ";" et ## par retour ligne.

Par contre

s/|#0-9#0-9*|//g  


cette ligne c'est pour supprimer le champs année du film?
parfois il peut il avoir du texte pour les années de sortie genre "mille neuf cent quatre vingt"

C'est peut-être ça le problème?
0
zipe31 Messages postés 36402 Date d'inscription dimanche 7 novembre 2010 Statut Contributeur Dernière intervention 27 janvier 2021 6 407
3 janv. 2012 à 20:08
cette ligne c'est pour supprimer le champs année du film?
Oui.

parfois il peut il avoir du texte pour les années de sortie genre "mille neuf cent quatre vingt"
C'est peut-être ça le problème?

Ben oui ;-((
0
zipe31 Messages postés 36402 Date d'inscription dimanche 7 novembre 2010 Statut Contributeur Dernière intervention 27 janvier 2021 6 407
3 janv. 2012 à 20:18
Essaie avec "mise_en_forme.sed" comme ça :

s/||[^|]*||//1
s/\(## [^|]*|\)|[^|]*|/\1/g
s/||/";"/g
s/ ## /"\n"/g 
s/\([^;]*;[^;]*;\)\([^\n]*\n\)\(.*\)/\1\2\1\3/
P
D
0
mamiemando Messages postés 33079 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 23 avril 2024 7 749
3 janv. 2012 à 10:48
Effectivement la commande sed (awk et vim permettent aussi d'y parvenir) permet de répondre au problème. A première vue :
- il faut substituer tous les || en ;
- il faut substituer tous les ## en -

De base pour remplacer un motif "aaa" en la chaîne "bbb" et sur toutes les occurrences de aaa sur une ligne dans un fichier appelé toto, la syntaxe est :

sed -i 's/aaa/bbb/g' toto


... ou encore (pratique quand aaa ou bbb comportent des /) :

sed -i 's%aaa%bbb%g' toto


Exemple :

(mando@aldur) (~) $ cat toto 
"Martin Scorsese";"Mad Max||1979||Action||Raging Bull||1980##1981||Drame||Cannonball||1975||Action##Comédie##Drame"

(mando@aldur) (~) $ sed -i 's/||/;/g' toto

(mando@aldur) (~) $ cat toto 
"Martin Scorsese";"Mad Max;1979;Action;Raging Bull;1980##1981;Drame;Cannonball;1975;Action##Comédie##Drame"


Dans le cas général, aaa est en réalité une expression rationnelle (c'est pour cela que j'ai parlé de "motif"), il faut donc éventuellement regardé un cours à ce sujet :
https://fr.wikipedia.org/wiki/Expression_rationnelle

Tu peux également regarder le man de sed, tu verras que \1, \2 etc... permettent d'extraire des morceaux du motif (aaa dans mon premier exemple) en vue de de les réutiliser dans bbb. Tu as des exemples ici :
https://fr.wikipedia.org/wiki/Stream_Editor

Le truc c'est que tu sembles avoir plusieurs films par ligne, et du coup ce n'est pas super clair. Est-ce que tu as une ligne par réalisateur ou il peut y avoir d'autres cas de figure ? Ne perd pas de vue que tu peux lancer plusieurs commandes sed pour convertir ton fichier et que leur ordre est important.

Une fois le sed effectué tu pourras importer ton fichier grâce à la directive COPY FROM en SQL.
https://www.postgresql.org/docs/9.0/sql-copy.html

Bonne chance
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
yann747 Messages postés 128 Date d'inscription mardi 25 octobre 2011 Statut Membre Dernière intervention 13 octobre 2021 2
3 janv. 2012 à 15:30
Merci pour vos réponses, je teste ça je vous en dis des nouvelles :-)
0
J'ai testé vos solutions, ça marche bien! Top
par contre la structure du CSV que j'ai à traité à été "un peu" modifiée:

Les deux premiers champs du fichier source reviennent toujours, le quatrième doit être supprimé, (qu'il contienne "##" ou non)... Du coup "##" a pour seule fonction un retour ligne.
Le champ supprimé devient ensuite le deuxième après "##"

Schématiquement:
1 2 3 (4) 5 6 7 8 9##10 (11) 12 13 14 15 16##17 (18) 19 20 21 22 23

()= supprimé

Devient

1 2 3 5 6 7 8 9
1 2 10 12 13 14 15 16
1 2 17 19 20 12 22 23


Ps: chaque ligne au final a toujours 8 items.

Tout ça est un peu compliqué, j'espère être assez clair (pas sûr...)
J'ai fait des test cet après-midi, avec sed, mais sans succès...
Voici donc un nouvel exemple, cette fois-ci définitif:

Exemple

"Americain";"Martin Scorsese";"Mad Max||1979||Action||Mel Gibson||Joanne Samuel||Steve Bisley||Tim Burns ## Raging Bull||1980##1981||Drame||Robert De Niro||Cathy Moriarty||Joe Pesci||Frank Vincent ## Cannonball||1975||Action||David Carradine||Bill McKinney||Veronica Hamel||Gerit Graham" \retour ligne

"Americain";"Martin Scorsese";"Mad Max";"Action";"Mel Gibson";"Joanne Samuel";"Steve Bisley";"Tim Burns" \retour ligne
"Americain";"Martin Scorsese";"Raging Bull";"Drame";"Robert De Niro";"Cathy Moriarty";"Joe Pesci";"Frank Vincent" \retour ligne
"Americain";"Martin Scorsese";"Cannonball";"Action-Comédie-Drame";"David Carradine";"Bill McKinney";"Veronica Hamel";"Gerit Graham" \retour ligne

séparateur dans le champs: || (en nombre fixe)
Retour ligne: ## (en nombre variable)

Je sais, ça donne pas trop envie de répondre... :-/
0
zipe31 Messages postés 36402 Date d'inscription dimanche 7 novembre 2010 Statut Contributeur Dernière intervention 27 janvier 2021 6 407
3 janv. 2012 à 18:46
$ cat film.txt 
"Americain";"Martin Scorsese";"Mad Max||1979||Action||Mel Gibson||Joanne Samuel||Steve Bisley||Tim Burns ## Raging Bull||1980##1981||Drame||Robert De Niro||Cathy Moriarty||Joe Pesci||Frank Vincent ## Cannonball||1975||Action||David Carradine||Bill McKinney||Veronica Hamel||Gerit Graham"

$ cat mise_en_forme.sed 
s/|[#0-9][#0-9]*|//g 
s/||/";"/g
s/ ## /"\n"/g 
s/\([^;]*;[^;]*;\)\([^\n]*\n\)\(.*\)/\1\2\1\3/
P
D

$ sed -f mise_en_forme.sed film.txt 
"Americain";"Martin Scorsese";"Mad Max";"Action";"Mel Gibson";"Joanne Samuel";"Steve Bisley";"Tim Burns"
"Americain";"Martin Scorsese";"Raging Bull";"Drame";"Robert De Niro";"Cathy Moriarty";"Joe Pesci";"Frank Vincent"
"Americain";"Martin Scorsese";"Cannonball";"Action";"David Carradine";"Bill McKinney";"Veronica Hamel";"Gerit Graham"

$ 
0
Super Zipe31 ça marche impec! Toujours aussi fort avec sed!!!
:-)
merci beaucoup!
Je n'y arrive pas encore tout seul... mais je progresse à force de tester.
0