Modification des dernières entrées d'une liste séparée par des virgules

8

J'ai un énorme fichier texte qui ressemble à ceci:

36,53,90478,0.58699759849,0.33616,4.83449759849,0.0695335954050315,3
36,53,90478,0.58699759849,0.33616,4.83449759849,0.0695335954050315,8
36,53,90478,0.58699759849,0.33616,4.83449759849,0.0695335954050315,14
36,53,15596,0.58454577855,0.26119,2.24878677855,0.116147072052964,12

La sortie souhaitée est la suivante:

36,53,90478,0.58699759849,0.33616,4.83449759849,0.0695335954050315,MI-03
36,53,90478,0.58699759849,0.33616,4.83449759849,0.0695335954050315,MI-08
36,53,90478,0.58699759849,0.33616,4.83449759849,0.0695335954050315,MI-14
36,53,15596,0.58454577855,0.26119,2.24878677855,0.116147072052964,MI-12

J'ai essayé d'autres publications pertinentes ici et sur d'autres communautés, mais je n'ai pas pu obtenir exactement ce que je veux.

MISE À JOUR

C'est la question croisée (je voulais des réponses Unix / perl et des solutions batch / powershell pour cela.) Qui a des réponses intéressantes.

M--
la source

Réponses:

14

approche awk avecfonction sprintf (pour ajouter des zéros non significatifs):

awk -F, -v OFS=',' '$8=sprintf("MI-%02d",$8);' file

Le résultat:

36,53,90478,0.58699759849,0.33616,4.83449759849,0.0695335954050315,MI-03
36,53,90478,0.58699759849,0.33616,4.83449759849,0.0695335954050315,MI-08
36,53,90478,0.58699759849,0.33616,4.83449759849,0.0695335954050315,MI-14
36,53,15596,0.58454577855,0.26119,2.24878677855,0.116147072052964,MI-12

-F,- définir une virgule ,comme séparateur de champ

$8 - pointe vers le huitième champ

%02d- format qui traite l'argument de la fonction comme un nombre à 2 chiffres


Notez que le dernier champ d'un enregistrement peut être présenté par$NF.

NF est une variable prédéfinie dont la valeur est le nombre de champs dans l'enregistrement en cours

Donc, $NFc'est la même chose que $8(pour votre entrée)

awk -F, -v OFS=',' '$(NF)=sprintf("MI-%02d", $(NF))' file
RomanPerekhrest
la source
1
Un mot d'avertissement (non pertinent dans cet exemple, mais pourrait s'appliquer dans d'autres cas): changer la valeur d'un des champs (ici: $ 8) "recalcule" tous les champs de la ligne, et a des effets secondaires: ex1: perd les séparateurs multiples ': echo "1   2 3    4" | awk '{$2=$2;print $0}'donne: 1 2 3 4(il ne reste qu'un espace (ou OFS) entre les champs). ex2) echo "1,,,2,3,,,,4" | awk -F',' '{$2=$2;print $0}'donne: 1   2 3    4(les virgules sont devenues des espaces). Il pourrait y avoir d'autres effets secondaires. Testez et adoptez une autre approche (gsub sur une variable de copie de $ 0, par exemple) si l'attribution d'un champ a des effets secondaires néfastes.
Olivier Dulac
3

Vous pouvez essayer d'utiliser awk:

awk 'BEGIN { FS = OFS = "," } { $NF = sprintf("MI-%02d", $NF); } 1' file
taliezin
la source
2

Voici la solution Perl:

$ perl -F',' -lane '$last=$#F;$F[$last]=sprintf("MI-%02d",$F[$last]);print join ",", @F' input.txt                                       
36,53,90478,0.58699759849,0.33616,4.83449759849,0.0695335954050315,MI-03
36,53,90478,0.58699759849,0.33616,4.83449759849,0.0695335954050315,MI-08
36,53,90478,0.58699759849,0.33616,4.83449759849,0.0695335954050315,MI-14
36,53,15596,0.58454577855,0.26119,2.24878677855,0.116147072052964,MI-12

L' -aindicateur nous permet de traiter l'entrée comme un tableau, en fonction du séparateur spécifié avec -F. Fondamentalement, nous modifions le dernier élément de ce tableau et le reconstruisons via la joincommande.

Sergiy Kolodyazhnyy
la source
Merci pour votre réponse. Cela aide si quelqu'un a besoin de Perl, mais c'est toujours sprintfl'idée centrale de votre réponse. Pas comme si ce n'était pas bien, juste ne pas proposer quelque chose de différent de la réponse acceptée. +1 de toute façon.
M--
1
@Masoud bien, la raison principale ici est parce qu'elle sprintf()est utilisée généralement lors de l'écriture d'une chaîne de format spécifique dans une variable, c'est pourquoi elle est utilisée dans de nombreuses autres langues. Je peux également l'écrire en Python - Python n'en a pas, sprintf()mais l'idée de base sera la même, en écrivant une chaîne formatée dans une variable. Alternativement, nous pouvons opérer directement sur les éléments du tableau et simplement les imprimer. Avec ce type de questions, il y a une quantité limitée de solutions, c'est essentiellement ce que j'essaie de dire
Sergiy Kolodyazhnyy
1

Avec des données d'entrée comme:

36,53,90478,0.58699759849,0.33616,4.83449759849,0.0695335954050315,3  
36,53,90478,0.58699759849,0.33616,4.83449759849,0.0695335954050315,8  
36,53,90478,0.58699759849,0.33616,4.83449759849,0.0695335954050315,14  
36,53,15596,0.58454577855,0.26119,2.24878677855,0.116147072052964,12  

dans text.csv

le code ci-dessous

awk -F"," '{ i = 0;
  MyOutLine = "";
  j = NF - 1;
  while ( i < j ) {
    i++;
    MyOutLine = MyOutLine""$i",";
  }
  i++;
  x = sprintf( "%.2i", $i );
  y = "MI-"x;
  MyOutLine = MyOutLine""y;
  print MyOutLine; }' ./text.csv  

produit une sortie comme:

36,53,90478,0.58699759849,0.33616,4.83449759849,0.0695335954050315,MI-03
36,53,90478,0.58699759849,0.33616,4.83449759849,0.0695335954050315,MI-08
36,53,90478,0.58699759849,0.33616,4.83449759849,0.0695335954050315,MI-14
36,53,15596,0.58454577855,0.26119,2.24878677855,0.116147072052964,MI-12
Norme
la source
1

Tcl

Voici ma solution, faite en utilisant Tcl qui lit à partir du fichier input.csv et met le résultat dans le fichier output.csv

set in [open input.csv]
set out [open output.csv w]

while {![eof $in]} {
   set line [gets $in]
   set last_comma_pos [string last , $line]
   puts $out [string range $line 0 $last_comma_pos][format MI-%02d [string range $line $last_comma_pos+1 end]]
}

close $in
close $out

manifestation

sergiol
la source