Alterando as últimas entradas em uma lista delimitada por vírgula

8

Eu tenho um arquivo de texto enorme que se parece com isso:

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

A saída desejada é esta:

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

Eu tentei outros posts relevantes aqui e em outras comunidades, mas não consegui exatamente o que queria.

ATUALIZAR

Essa é a pergunta cruzada (eu queria respostas Unix / perl e soluções batch / powershell para isso.) Que tem respostas interessantes.

M--
fonte

Respostas:

14

abordagem awk com afunção sprintf (para adicionar zeros à esquerda):

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

A saída:

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,- definir vírgula ,como separador de campo

$8 - aponta para o oitavo campo

%02d- formato que trata o argumento da função como um número de 2 dígitos


Observe que o último campo em um registro pode ser apresentado por$NF.

NF é uma variável predefinida cujo valor é o número de campos no registro atual

Então, $NFé o mesmo que $8(para sua entrada)

awk -F, -v OFS=',' '$(NF)=sprintf("MI-%02d", $(NF))' file
RomanPerekhrest
fonte
1
Uma palavra de advertência (irrelevante neste exemplo, mas pode ser aplicada em outros casos): alterar o valor de um dos campos (aqui: US $ 8) "recalcula" todos os campos da linha e possui efeitos colaterais: ex1: perde vários separadores ': echo "1   2 3    4" | awk '{$2=$2;print $0}'fornece: 1 2 3 4(apenas 1 espaço (ou OFS) restante entre os campos). ex2) echo "1,,,2,3,,,,4" | awk -F',' '{$2=$2;print $0}'fornece: 1   2 3    4(vírgulas se tornaram espaços). Pode haver outros efeitos colaterais. Teste e adote outra abordagem (gsub em uma variável de cópia de $ 0, por ex) se a atribuição de um campo tiver efeitos colaterais prejudiciais.
21717 Olivier Dulac
3

Você pode tentar usar awk:

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

Aqui está a solução 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

O -asinalizador permite tratar a entrada como matriz, com base no separador especificado com -F. Basicamente, alteramos o último item desse array e o reconstruímos via joincomando.

Sergiy Kolodyazhnyy
fonte
Obrigado pela sua resposta. Ajuda se alguém precisa de perl, mas ainda sprintfé a idéia central da sua resposta. Não é como se não estivesse certo, apenas não oferecendo algo diferente da resposta aceita. +1 de qualquer maneira.
M--
1
@ Bem, o principal motivo aqui é porque sprintf()é usado normalmente ao escrever uma sequência de formato específico em uma variável, e é por isso que é usada em muitos outros idiomas. Também posso escrever em Python - o Python não tem, sprintf()mas a ideia principal será a mesma, independentemente - escrever uma string formatada em uma variável. Como alternativa, podemos operar itens de matriz diretamente e apenas imprimi-los. Com este tipo de perguntas há quantidade finita de soluções, basicamente, é o que estou tentando dizer
Sergiy Kolodyazhnyy
1

Com dados de entrada como:

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  

em text.csv

o código abaixo

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  

produz resultados como:

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
Norma
fonte
1

Tcl

Aqui está minha solução, feita usando Tcl, que lê o arquivo input.csv e coloca o resultado no arquivo 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

demonstração

sergiol
fonte