Processamento de texto - Substituir segundo do início e segundo do final por linha

4

Eu tenho arquivos csv ruins e preciso adicionar algumas citações

Em

field,field2,text field with potential commas,field4,field5
field,field2,text fie,ld with pot,ential commas,field4,field5
field,field2,text field with, potential commas,field4,field5

Fora

field,field2,"text field with potential commas",field4,field5
field,field2,"text fie,ld with pot,ential commas",field4,field5
field,field2,"text field with, potential commas",field4,field5

sed 's/,/,"/2' adicionará a primeira cotação, mas como posso fazer o mesmo com a segunda ocorrência para trás a partir do final, para cada linha?

sed, awk, perl e outros métodos são bem-vindos. Os arquivos são alguns milhões de linhas, a velocidade é apreciada.

    
por stiq 14.05.2018 / 20:05

5 respostas

5

Aqui está uma maneira awk : se houver mais de cinco campos delimitados por vírgula, percorra os campos "intermediários" concatenando-os antes de imprimir o novo campo entre aspas, seguido pelos dois campos finais:

awk -f awkscript.awk < input

Com o seguinte como awkscript.awk :

BEGIN {
  OFS=","
  FS=","
}
{
        if (NF > 5) {
                middle=""
                for(i=3; i <= NF-2; i++)
                        middle=(middle ? middle"," : "")$i
                print $1, $2, "\""middle"\"", $(NF-1), $NF
        } else {
                print $1, $2, "\""$3"\"", $4, $5
        }
}
    
por 14.05.2018 / 20:25
3

Usando sed , você faria:

sed 's/,/,"/2; s/\(,[^,]*,[^,]*\)$/"/' infile

Este s/,/,"/2 substitui apenas o segundo. Esse s/\(,[^,]*,[^,]*\)$ corresponde a ,anything-not-a-comma,anything-not-a-comma do final $ da linha como um grupo corresponde à referência anterior de e, em seguida, na peça de reposição após a adição de uma cotação, nós o trazemos de volta "

    
por 14.05.2018 / 20:21
3

Aqui está uma abordagem estupidamente simples, embora provavelmente não seja a mais eficiente:

sed 's/,/,"/2' input.csv | rev | sed 's/,/,"/2' | rev > output.csv
    
por 15.05.2018 / 04:18
2

perl: esta versão cita todos os campos e manipula todas as citações "interiores"

$ cat file
field,field2,text field with potential commas,field4,field5
field,field2,text fie,ld with pot,ential commas,field4,field5
field,field2,text field with, potential commas,field4,field5
field,field2,"Just drive," she said,f4,f5

$ perl -F, -lane '
    @result = ( splice(@F,0,2), undef, splice(@F,@F-2,2) );
    $result[2] = join ",", @F;
    print join ",", map {s/"/""/g; qq/"$_"/} @result
' file 

"field","field2","text field with potential commas","field4","field5"
"field","field2","text fie,ld with pot,ential commas","field4","field5"
"field","field2","text field with, potential commas","field4","field5"
"field","field2","""Just drive,"" she said","f4","f5"

A primeira linha de código extrai os primeiros 2 e os últimos 2 campos de dados.
A segunda linha coleta todo o resto dos dados como o terceiro campo.
A terceira linha é exibida como CSV.

    
por 14.05.2018 / 21:05
0
sed -e '
   s/,/&\n/2
   s/\n\(.*\)\(,.*,.*\)/""/
'    input.csv


 perl -pe '
    my $p;
    while ( /,/g ) {
       s/\G/"/,next if ++$p == 2;

       last if s/,\G(?=.*,)(?!.*,.*,)/",/;  # looks for 2nd last comma
    }
 '    input-file.csv



 perl -pe '
      substr($_, index($_, q/,/, 1+index($_, q/,/)), 1) = q/,"/;

      substr($_, rindex($_, q/,/, -1+rindex($_, q/,/)), 1) = q/",/;
 '     csvfile

Aqui, invocamos a função index duas vezes para obter a posição da segunda vírgula da esquerda. Em seguida, coloque uma marca de cotação adjacente a ela usando a função substr agora que a posição foi verificada.

Da mesma forma, invocamos a função rindex e fazemos a alteração correspondente.

    
por 14.05.2018 / 21:03