Modifica delle ultime voci in un elenco delimitato da virgole


8

Ho un enorme file di testo che assomiglia a questo:

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

L'output desiderato è questo:

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

Ho provato altri post pertinenti qui e su altre community ma non sono riuscito a ottenere esattamente quello che volevo.

AGGIORNARE

Questa è la domanda incrociata (per questo volevo sia risposte Unix / perl sia soluzioni batch / powershell) che abbia risposte interessanti.

Risposte:


14

approccio awk con lafunzione sprintf (per aggiungere zeri iniziali):

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

Il risultato:

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,- imposta la virgola ,come separatore di campi

$8 - indica l'ottavo campo

%02d- formato che tratta l'argomento della funzione come numero a 2 cifre


Nota , l'ultimo campo in un record può essere presentato da$NF.

NF è una variabile predefinita il cui valore è il numero di campi nel record corrente

Quindi, $NFè lo stesso di $8(per il tuo input)

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

1
Un avvertimento (irrilevante in questo esempio, ma potrebbe applicarsi in altri casi): la modifica del valore di uno dei campi (qui: $ 8) "ricalcola" i campi dell'intera linea e ha effetti collaterali: ex1: perde i separatori multipli ': echo "1   2 3    4" | awk '{$2=$2;print $0}'dà: 1 2 3 4(solo 1 spazio (o OFS) lasciato tra i campi). ex2) echo "1,,,2,3,,,,4" | awk -F',' '{$2=$2;print $0}'dà: 1   2 3    4(le virgole diventano spazi). Potrebbero esserci altri effetti collaterali. Prova e adotta un altro approccio (gsub su una variabile di copia di $ 0, ad esempio) se l'assegnazione di un campo ha effetti collaterali dannosi.
Olivier Dulac,

3

Puoi provare a usare awk:

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

2

Ecco la soluzione 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

Il -aflag ci consente di trattare l'input come array, in base al separatore specificato con -F. Fondamentalmente alteriamo l'ultimo elemento in quell'array e lo ricostruiamo tramite joincomando.


La ringrazio per la risposta. Aiuta se qualcuno ha bisogno di perl ma sprintfè ancora l'idea centrale della tua risposta. Non come se non fosse giusto, semplicemente non offrendo qualcosa di diverso dalla risposta accettata. +1 comunque.
M--

1
@Masoud bene, il motivo principale qui è perché sprintf()viene utilizzato in genere quando si scrive una stringa di formato specifico in una variabile, motivo per cui viene utilizzato in molte altre lingue. Posso scriverlo anche in Python - Python non ha sprintf()ma l'idea di base sarà la stessa a prescindere - scrivere una stringa formattata in una variabile. In alternativa, possiamo operare direttamente sugli articoli dell'array e semplicemente stamparli. Con questo tipo di domande c'è una quantità
limitata

1

Con dati di input come:

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  

in text.csv

il codice qui sotto

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  

produce output come:

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

1

Tcl

Ecco la mia soluzione, fatta usando Tcl che legge dal file input.csv e inserisce il risultato nel file 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

dimostrazione

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.