Como prefixar os valores de uma coluna com um apóstrofo (')?

4

Eu tenho um arquivo CSV com várias colunas e milhares de registros, preciso prefixar todos os valores de uma das colunas (digamos, segunda coluna) com um apóstrofo ' , exceto no primeira linha ou linha de cabeçalho, pode haver um forro simples para isso. Como eu poderia conseguir isso usando awk ou sed ? Por favor note, eu posso ter várias vírgulas nos valores que estão entre aspas duplas.

Dados da amostra:

"col1","col2","col3","col4","col5"
"value11","value12","value13","value14","value15"
"value21","value22","value23","value24","value25"
"value31","value32","value33","value34","value35"

Resultado esperado:

"col1","col2","col3","col4","col5"
"value11","'value12","value13","value14","value15"
"value21","'value22","value23","value24","value25"
"value31","'value32","value33","value34","value35"
    
por Dhruuv 23.10.2013 / 20:17

4 respostas

5

sed:

sed '2,$s/^\("[^"]*","\)/'"'"/ test.in

Usando os EREs para se livrar de alguns dos escapes:

sed -E '2,$s/^("[^"]*",")/'"'"/ test.in

awk:

awk -F, 'NR>1{sub(/^"/,"\"'"'"'",$2)}1' test.in

Se você não quiser se preocupar com as citações, use o código de escape:

awk -F, '{sub(/^"/,"\"\x27",$2)}1' test.in
    
por 23.10.2013 / 20:24
5

Usando o Perl:

perl -pi -e '
             BEGIN{
                 $column_number = 2; # Change as needed
                 $column_number--;
                 $apostrophe = chr 39;
             }
             next unless $this_is_data++; # Skip the first line
             s@ ^((?:"[^"]+"\s*,){$column_number}) "@$1"$apostrophe@x
           ' your_file

Isso pressupõe que seus campos não contenham citações com escape de barra invertida.

    
por 23.10.2013 / 20:35
5

Aqui está um embaraço:

$ gawk -F'","' -v var="'" -v OFS='","' 'NR>1{$2=var$2;} 1' foo.csv 

A opção -v permite definir variáveis acessíveis ao script gawk . Nesse caso, var é ' e OFS (o separador do campo de saída) é "," , o mesmo que o separador do campo de entrada ( -F ). Em seguida, verificamos que essa não é a primeira linha ( NR>1 ) e adicionamos o valor de var à segunda coluna. Finalmente, o 1 é apenas um truque, ele é avaliado como true, o que faz com que gawk imprima a linha. É equivalente a adicionar um print; , mas mais curto.

Se você deseja executar isso em uma coluna diferente, basta alterar $2=var$2; para $N=var$N , em que N é o número da coluna em que você está interessado.

Você também pode fazer isso em perl (naturalmente, você pode fazer tudo em perl):

$ perl -F'\",\"' -ane '$.>1 && do{$F[1]=chr(39).$F[1]}; 
                       print join("\",\"",@F)' foo.csv

A opção -a faz as linhas de entrada perl divididas, como o gawk, que as salva na matriz @F (as matrizes perl começam em 0, então a segunda coluna será $F[1] , a terceira $F[2] etc. ). O -F (novamente como gawk ) define o separador do campo de entrada. Portanto, verificamos se o número da linha é maior que um ( $.>1 ) e, se for, adicione o valor de chr 39 (a ' , obrigado @josephR) a ele. Finalmente, usamos join para conectar cada elemento na matriz @F com "," e imprimir a sequência resultante.

    
por 23.10.2013 / 20:25
4

Um sed simples será o seguinte:

$ sed 's/","/","\x27/' afile
"col1","'col2","col3","col4","col5"
"value11","'value12","value13","value14","value15"
"value21","'value22","value23","value24","value25"
"value31","'value32","value33","value34","value35"

Detalhes

Estamos pesquisando a primeira ocorrência de "," e substituindo-a por ","' . No entanto, escapar do backtick pode ser complicado. Então, basta colocar seu código de escape hexadecimal equivalente, \x27 .

Seu problema

Isso pode ser adaptado dessa forma para limitar as alterações apenas às linhas desejadas.

$ cat <(head -n +1 afile) <(tail -n +2 afile | sed 's/","/","\x27/')
"col1","col2","col3","col4","col5"
"value11","'value12","value13","value14","value15"
"value21","'value22","value23","value24","value25"
"value31","'value32","value33","value34","value35"

Ou você pode pular a primeira linha completamente, usando sed se souber o truque 8 -):

$ sed '2,$s/","/","\x27/' afile
"col1","col2","col3","col4","col5"
"value11","'value12","value13","value14","value15"
"value21","'value22","value23","value24","value25"
"value31","'value32","value33","value34","value35"

Isso diz sed para levar apenas a segunda linha até a última linha ( $ ) e executá-las pela pesquisa e substituição.

    
por 23.10.2013 / 20:23

Tags