Substitua a vírgula pela barra vertical |, exceto quando estiver entre aspas duplas e remova as aspas duplas

6

Arquivo1

12584,"Capital of America, Inc.",,HORIZONCAPITAL,USA,......etc
25841,"Capital of America, Inc.",,HORIZONCAPITAL,USA,......etc
87455,"Capital of America, Inc.",,HORIZONCAPITAL,USA,......etc

Saída

12584|Capital of America, Inc.||HORIZONCAPITAL|USA|......etc
25841|Capital of America, Inc.||HORIZONCAPITAL|USA|......etc
87455|Capital of America, Inc.||HORIZONCAPITAL|USA|......etc

Eu tenho um arquivo csv, que eu tenho que converter em um arquivo de texto delimitado com pipe (|) Eu fiz o script de shell sed 's/^/"/;s/,/|/g;s/$/"/' $File > $Output

Mas o problema é o campo "Capital of America, Inc." contém uma vírgula, que também é substituída pelo pipe (|). Então eu só queria substituir tudo, com pipe, exceto não dentro do valor é dada aspas duplas "".

Existe algum script de shell para fazer isso?

    
por Juhan 25.07.2018 / 10:46

7 respostas

21

Usando csvkit :

$ csvformat -D '|' file.csv
12584|Capital of America, Inc.||HORIZONCAPITAL|USA|......etc
25841|Capital of America, Inc.||HORIZONCAPITAL|USA|......etc
87455|Capital of America, Inc.||HORIZONCAPITAL|USA|......etc

csvkit é uma coleção de ferramentas de manipulação / consulta de CSV escritas em Python. Eles fazem a análise CSV adequada e csvformat pode ser usado para substituir o delimitador de vírgula padrão por qualquer outro caractere. O utilitário garantirá que o resultado seja corretamente citado de acordo com as regras do CSV.

    
por 25.07.2018 / 10:54
8

Pelo menos em sistemas baseados em Debian, você deve conseguir instalar o csvtool

baseado em OCaml
$ csvtool -u '|' cat file.csv
12584|Capital of America, Inc.||HORIZONCAPITAL|USA|......etc
25841|Capital of America, Inc.||HORIZONCAPITAL|USA|......etc
87455|Capital of America, Inc.||HORIZONCAPITAL|USA|......etc

Você também pode usar o módulo Text::CSV do Perl:

$ perl -MText::CSV -lne '
  BEGIN{$p = Text::CSV->new()} 
  print join "|", $p->fields() if $p->parse($_)
' file.csv
12584|Capital of America, Inc.||HORIZONCAPITAL|USA|......etc
25841|Capital of America, Inc.||HORIZONCAPITAL|USA|......etc
87455|Capital of America, Inc.||HORIZONCAPITAL|USA|......etc
    
por 25.07.2018 / 11:06
2

Para corrigir seu problema:

awk 'BEGIN{FS=",";OFS="|";} {print $1,$2","$3,$4,$5,$6,$7}' Test | tr -d \"

para problemas generalizados como este, o GNU awk tem uma variável especial FPAT para descrever os campos:

awk -vFPAT='[^,]*|("[^"]*")' -vOFS='|' '{$1=$1;print}' Test | tr -d \"
12584|Capital of America, Inc.||HORIZONCAPITAL|USA|......etc
25841|Capital of America, Inc.||HORIZONCAPITAL|USA|......etc
87455|Capital of America, Inc.||HORIZONCAPITAL|USA|......etc

com as ferramentas awk e sed , você não precisa de um pacote extra. EDITAR como Issak mencionado, eu atualizo minha resposta:

awk -vFPAT='[^,]*|(["].*["])' -vOFS='|' '{print $1,$2,$3,$4,$5,$6}' Test | sed 's/\"//g'
    
por 25.07.2018 / 11:27
2

Usando o SED:

Opção 1:

sed -e 's#,\([^ ]\)#|#g;s#"##g;s#|,#||#g' file

12584|Capital of America, Inc.||HORIZONCAPITAL|USA|......etc
25841|Capital of America, Inc.||HORIZONCAPITAL|USA|......etc
87455|Capital of America, Inc.||HORIZONCAPITAL|USA|......etc
  • \([^ ]\) substitui todas as vírgulas que não são seguidas por espaço.
  • Em seguida, remova " e substitua a vírgula precedida por | .

geralmente em um contexto, uma vírgula estará no espaço. Se não no seu caso, tente o código abaixo.

Opção 2:

sed -e  's#^#\n#;:a;s#\n\([^,"]\|"[^"]*"\)#\n#;ta;s#\n,#|\n#;ta;s#\n##;s#"##g' file

12584|Capital of America, Inc.||HORIZONCAPITAL|USA|......etc
25841|Capital of America, Inc.||HORIZONCAPITAL|USA|......etc
87455|Capital of America, Inc.||HORIZONCAPITAL|USA|......etc
    
por 25.07.2018 / 11:29
1

awk , um caractere por vez

Examine cada linha de entrada, um caractere por vez. Alterne um contador q entre 0 e 1 sempre que você encontrar uma marca de aspas duplas " , de modo que q seja igual a 1 dentro de cada par de marcas de aspas duplas (ou seja, antes de cada < em> fechamento marca aspas duplas). Em seguida, dependendo de q , altere as vírgulas , nos caracteres de canal | . Após cada linha ter sido avaliada, imprima a linha modificada.

awk '{
  m=""
  q==0
  for (n=1;n<=length($0);n++) {
    p=substr($0,n,1)
    if (p=="\"") { p="" ; q=(q+1)%2 }
    if (p=="," && q==0) p="|"
    m=m p
    }
  print m
  }' file.csv

Entrada:

12584,"Capital of America, Inc.",,HORIZONCAPITAL,USA,......etc
25841,"Capital of America, Inc.",,HORIZONCAPITAL,USA,......etc
87455,"Capital of America, Inc.",,HORIZONCAPITAL,USA,......etc

Saída:

12584|Capital of America, Inc.||HORIZONCAPITAL|USA|......etc
25841|Capital of America, Inc.||HORIZONCAPITAL|USA|......etc
87455|Capital of America, Inc.||HORIZONCAPITAL|USA|......etc
    
por 25.07.2018 / 20:50
1

com perl autônomo:

perl -pe 's{"(.*?)"|,}{$1 // "|"}ge' < "$File" > "$Output"

(assume que os valores não contêm | , " ou caracteres de nova linha).

    
por 25.07.2018 / 15:13
0

Com um script Python muito curto usando csv module:

import csv,sys

with open(sys.argv[1]) as csvfile:
    csvr = csv.reader(csvfile)
    for line in csvr:
        print('|'.join(line))

Isso funciona da seguinte maneira:

$ python3 csvfile.py input.csv
12584|Capital of America, Inc.||HORIZONCAPITAL|USA|......etc
25841|Capital of America, Inc.||HORIZONCAPITAL|USA|......etc
87455|Capital of America, Inc.||HORIZONCAPITAL|USA|......etc
    
por 26.07.2018 / 07:26