Recorte os SUBSTRINGS para um tamanho específico em um arquivo CSV

1

Eu tenho um arquivo como abaixo, cat Test.csv

"pav",12345,"ABCD,EF;xyz23;15rtg",,
"xyz",,"C4DEF;x23yu;rtg",,

Após modificação:

cat Test.csv

"pav",12345,"AB;xy;15",,
"xyz",,"C4;x2;rt",,

O campo 3 contendo substrings delimitadas com " ; " precisa ser substituído por suas substrings

    
por Pavan 22.10.2017 / 08:56

4 respostas

0

O texto a seguir está usando csvkit , porque a análise de dados CSV que contêm vírgulas em campos com aspas com awk é propensa a erros .

Isso obterá a coluna três no formato correto:

csvcut -c 3 file.csv |
sed -r 's/^"|"$//g' |
awk -F';' -vOFS=';' '{ for (i=1; i<=NF; ++i) $i = substr($i, 0, 2) } { printf("\"%s\"\n", $0) }' >tmp-3rd

Para a entrada dada, isso produz

"AB;xy;15"
"C4;x2;rt"
  • csvcut vai cortar a terceira coluna.
  • sed removerá as aspas duplas dos dados, se aparecerem primeiro ou por último na linha.
  • O programa awk passará pelos campos ; -delimited e os reduzirá a um tamanho de dois caracteres por campo. Imprime os dados com aspas duplas em torno dele.
  • A saída é gravada no arquivo tmp-3rd .

Então, é apenas uma questão de remontar isso com os dados originais (isto está assumindo bash ou qualquer outro shell que possa fazer substituições de processo com <(...) ):

paste -d, <( csvcut -c 1,2 file.csv ) tmp-3rd <( csvcut -c 4,5 file.csv ) | csvformat
  • paste irá colocar as colunas juntas com vírgulas no meio.
  • A primeira substituição de processo produz as duas primeiras colunas do arquivo original e a segunda produz as duas últimas colunas. No meio, nós fornecemos a terceira coluna modificada.
  • Como uma etapa opcional, passamos os dados por meio de csvformat , o que irá citar ou desmarcar campos conforme necessário.

A saída será

pav,12345,AB;xy;15,,
xyz,,C4;x2;rt,,

Ignorando a necessidade do arquivo temporário:

paste -d, \
    <( csvcut -c 1,2 file.csv ) \
    <( csvcut -c 3 file.csv | sed -r 's/^"|"$//g' |
       awk -F';' -vOFS=';' '{ for (i=1; i<=NF; ++i) $i = substr($i, 0, 2) } { printf("\"%s\"\n", $0) }' ) \
    <( csvcut -c 4,5 file.csv ) | csvformat
    
por 22.10.2017 / 09:51
0

com perl

Assumindo que ; esteja apenas no terceiro campo

$ perl -pe 's/"\K[^;"]*;[^"]*(?=")/$&=~s|([^;]{2})[^;]+|$1|gr/e' ip.txt
"pav",12345,"AB;xy;15",,
"xyz",,"C4;x2;rt",,
  • "\K para corresponder a " antes da cadeia de interesse e (?=") para corresponder a " após uma cadeia de interesse. Mas o " não faz parte da string capturada, uma vez que estas são lookarounds
  • [^;"]*;[^"]* corresponde a qualquer caractere não ; ou " seguido por ; seguido por não " caracteres
  • $&=~s|([^;]{2})[^;]+|$1|gr para executar outra substituição na string correspondente
  • e modifier permite usar o código Perl na seção de substituição


Para restringir apenas o 3º campo

$ cat ip.txt 
"pav",12345,"ABCD,EF;xyz23;15rtg",,
"xyz",,"C4DEF;x23yu;rtg",,
"foo;12,23;good",124,253
12,5232,"xyz","ijk;5545;62"

$ perl -pe 's/^("[^"]*",|[^,]*,){2}"\K[^;"]*;[^"]*(?=")/$&=~s|([^;]{2})[^;]+|$1|gr/e' ip.txt
"pav",12345,"AB;xy;15",,
"xyz",,"C4;x2;rt",,
"foo;12,23;good",124,253
12,5232,"xyz","ijk;5545;62"
    
por 22.10.2017 / 10:46
0

Solução 3.x robusta e robusta Python (com base em objeto csv.reader ):

parse_csv.py script:

import csv, sys
with open(sys.argv[1]) as f:
    reader = csv.reader(f)
    for l in reader:
        l = [s if ';' not in s else ';'.join(_[:2] for _ in s.split(';')) for s in l]
        print(','.join(i if not i or i.isnumeric() else '"{}"'.format(i) for i in l))

Uso:

python3 parse_csv.py Test.csv

A saída:

"pav",12345,"AB;xy;15",,
"xyz",,"C4;x2;rt",,

O módulo csv do Python fornece suporte robusto e flexível para csv data.

    
por 22.10.2017 / 12:13
0

Solução complexa AWK (analisando csv data):

awk -v FPAT='"[^"]+"|[^",]+|,,' '{ 
           for (i=1;i<=NF;i++) { 
               if ($i~/^".*;./) { 
                   len=split($i,a,";"); v=substr(a[1],1,3); 
                   for (j=2;j<=len;j++) v= v";"substr(a[j],1,2);
                   v=v"2"
               }  printf "%s%s",(v? v: ($i~/^,,/? (i==NF? ",":""):$i )),
                                (i==NF? ORS:OFS); v="" 
           } 
       }' OFS=',' Test.csv
  • FPAT='"[^"]+"|[^",]+|,,' - padrão de regex complexo que define o valor do campo

  • if ($i~/^".*;./) ... - se o campo atual $i contiver ; caractere (s)

  • len=split($i,a,";") - divide o valor do campo $i na matriz a pelo separador ; . len é atribuído com o número de elementos / pedaços criados

  • v=substr(a[1],1,3); - capturando o primeiro fragmento do comprimento necessário, incluindo " char, por ex. "AB será extraído de "ABCD,EF

  • for (j=2;j<=len;j++) ... - iterando pelos blocos / itens restantes

  • v=v"2" - adicione aspas duplas " à sequência processada v . 3 é o código octal ASCII que representa o caractere de aspas duplas " .

  • ($i~/^,,/? (i==NF? ",":""):$i ) - cada campo vazio ,, é recriado com vírgula única , e delimitador comum (também , ). Isso é para evitar confusão redundante de vírgulas como "pav",,,

  • (i==NF? ORS:OFS) - ao encontrar o último campo i==NF - separador de registro de saída de impressão ORS , caso contrário - imprima separador de saída arquivado OFS

A saída:

"pav",12345,"AB;xy;15",,
"xyz",,"C4;x2;rt",,
    
por 22.10.2017 / 09:45