2017-10-09 4 views
-1

J'ai un fichier séparé par des tabulations comme ceci:2ème colonne séparée séparés par des virgules liste de nouvelles lignes, hériteront valeur en 1ère colonne par nouvelle ligne

ID1 blue 
ID2 yellow,blue 
ID3 green,yellow,red 
ID4 red 
1D5 red,purple 

Pour la deuxième colonne, je dois séparer le liste des virgules, chaque couleur sur sa propre ligne, et pour chaque nouvelle ligne, j'ai besoin de conserver le numéro d'identification.

Je pensais utiliser sed pour remplacer chaque virgule par une nouvelle ligne, mais je ne sais plus comment ajouter l'ID associé. Awk ou Perl? Après de longues recherches, je ne peux pas trouver la réponse ...

résultats définitifs auront pas des virgules et ressembler à ceci:

Résultat final:

ID1 blue 
ID2 yellow 
ID2 blue 
ID3 green 
ID3 yellow 
ID3 red 
ID4 red 
1D5 red 
1D5 purple 

Toute aide très appréciée. Cette question est très similaire à Bash turning single comma-separated column into multi-line string, mais ma colonne 1 est toujours une seule valeur alors que la question similaire a plusieurs valeurs séparées par une virgule dans la colonne 1. Je n'ai pas trouvé ma solution en examinant la question similaire. En espérant que cette question est assez distincte pour rester sur ce site et, espérons-le, aider les autres aussi.

Répondre

1
$ awk -F'[\t,]' '{for (i=2;i<=NF;i++) print $1, $i}' file 
ID1 blue 
ID2 yellow 
ID2 blue 
ID3 green 
ID3 yellow 
ID3 red 
ID4 red 
1D5 red 
1D5 purple 
+1

Merci beaucoup, Ed! – Cath

0

Ce programme awk simple devrait le faire:

$ awk -F'\t' '{ n=split($2,arr,","); for(i=1;i<=n;i++) print $1,arr[i] }' file 
ID1 blue 
ID2 yellow 
ID2 blue 
ID3 green 
ID3 yellow 
ID3 red 
ID4 red 
1D5 red 
1D5 purple 

Nous avons partagé la ligne dans les champs de l'onglet (\t), puis pour chaque ligne de séparation le second champ sur des virgules (,) avec split(). Enfin, nous parcourons tous les éléments du tableau arr et imprimons une ligne par paire (premier champ, élément de tableau).

0

Votre question a été taguée avec différents langages utilitaires/colles, y compris Perl, donc cette réponse décrit des solutions utilisant le langage de programmation Perl.

Voici un Perl solution one-liner:

perl -lF/\\t/ -e 'print "$F[0] $_" for split /,/, $F[1]' test.txt 

Suivant un fichier délimité par des tabulations comme décrit dans la question ce produit la sortie suivante:

ID1 blue 
ID2 yellow 
ID2 blue 
ID3 green 
ID3 yellow 
ID3 red 
ID4 red 
1D5 red 
1D5 purple 

Cela fonctionne à peu près la même que le suivant script Perl complet:

while (<>) { 
    chomp; 
    next unless length; 
    my ($id, $colors) = split /\t/, $_; 
    print "$id $_\n" foreach split /,/, $colors; 
} 

Dans ces solutions, j'ai utilisé \t pour séparer les onglets, bien que les données d'exemple que vous avez fournies semblaient plutôt être délimitées par des espaces, et non par des tabulations. Si c'est le cas que vos données sont simplement délimitées par des espaces, remplacez \t par \s+.

Voilà comment celui-liner fonctionne:

-l ensembles auto-Chomp pour l'entrée, et l'auto-retour à la ligne pour la sortie. Le commutateur -F définit implicitement -a (ce qui signifie auto-split en @F) et -n (ce qui signifie parcourir les fichiers d'entrée transmis sur la ligne de commande).

Le -F/\\t/ signifie la division automatique sur l'expression rationnelle /\t/, ou en d'autres termes, sur les caractères de tabulation, remplissant @F avec les résultats. (Vous pouvez changer \\t-\\s+ si vos données sont plus généralement des espaces délimités.)

Par conséquent, pour chaque ligne d'entrée, $F[0] contiendra le champ IDx et $F[1] contiendra des couleurs telles que yellow,blue.

Le commutateur de ligne de commande -e moyen d'évaluer le code suivant, et parce que nous avons -n implicite dans -F nous itérer sur le fichier et exécuter le code une fois par ligne des fichiers d'entrée.

Et le code que nous passons est:

print "$F[0] $_" foreach split /,/, $F[1] 

Ce qui signifie que chaque ligne du fichier, pour chaque élément dans la liste des couleurs, imprimer l'ID (stocké dans $F[0]), suivi par la couleur (stockée au $_).

on dérive les couleurs individuellement en divisant $F[1], qui peut contenir yellow,blue sur la virgule, et le remplissage $_ pour chaque couleur (en utilisant la boucle foreach).

décrivant la version du script:

while(<>) {...} lit une ligne à la fois des fichiers définis sur la ligne de commande (ou de STDIN), et pour chaque ligne Remplit $_.

Documentation pertinente:

Chaque installation complète de navires Perl avec la commande perldoc, qui peut être appelé avec le nom d'un morceau de la documentation de Perl pour lire.

Voir les éléments suivants:

  • perldoc perlrun - Une explication des commutateurs de ligne de commande de Perl.
  • perldoc perlintro - Une brève introduction à Perl.
  • perldoc perlre - Présentation générale des expressions régulières de Perl.
  • perldoc -f split - Une explication du fonctionnement de la fonction split de Perl.
  • perldoc perlsyn - Une description des structures de contrôle de Perl telles que les boucles foreach.
  • perldoc perlop - Une vue d'ensemble des opérateurs de Perl, y compris <>.

De plus, si vos données est plus complexe que montré, en utilisant des constructions telles que guillemets et les échappements de délimiteurs, vous devriez probablement préférez le module Text::CSV CPAN pour analyser le fichier TSV/CSV.

+0

Merci pour tous les détails, Davido! – Cath

0

Cela pourrait fonctionner pour vous (GNU sed):

sed -r 's/^((\S+\s+)[^,]+),/\1\n\2/;P;D' file 

Remplacer chaque , par un saut de ligne suivi de la touche et son des espaces (onglet).

0

En poursuivant votre navigation sur ce site, vous pouvez aussi nous contacter.

awk '{gsub(/,/,RS $1"&");gsub(/,/," ")} 1' Input_file 

Explication:

gsub (/, /, RS 1" $ & «): Utilisation de l'utilitaire de remplacement global de awk pour remplacer chaque virgule dans une ligne avec RS (nouveau line) $ 1 (premier champ de cette ligne) "&" indique une virgule ici (indique une variable/regex que nous mentionnons comme étant substituée).

gsub (/,/« , «): Encore une fois en utilisant l'utilitaire de remplacement global à awk, ainsi au-dessus gsub fera INPUT_FILE à se présenter comme suit.

ID1 blue 
ID2 yellow 
ID2,blue 
ID3 green 
ID3,yellow 
ID3,red 
ID4 red 
1D5 red 
1D5,purple 

qui n'est pas la sortie de notre OP, donc à nouveau en substituant à l'échelle mondiale par des virgules avec un espace simple pour obtenir la sortie correcte comme suit.

ID1 blue 
ID2 yellow 
ID2 blue 
ID3 green 
ID3 yellow 
ID3 red 
ID4 red 
1D5 red 
1D5 purple 
+1

Merci, Ravinder! – Cath

+0

@Cath, vous êtes les bienvenus, heureux que cela vous a aidé. Voir ce https://stackoverflow.com/help/someone-answers profiter de l'apprentissage et le partage des connaissances, acclamations :) – RavinderSingh13