Substituindo vírgula se encontrada entre aspas duplas em um arquivo CSV usando sed

Substituindo vírgula se encontrada entre aspas duplas em um arquivo CSV usando sed

Eu tenho um arquivo CSV que preciso carregar em uma tabela MySQL. Conto em identificar as colunas finalizadas pelo ,caractere. É por isso que é importante que o ,não apareça em outro lugar que não seja um separador de colunas.

Encontrei algumas linhas que contêm uma coluna ,entre aspas duplas. por exemplo, uma linha como esta:

12,"name, brand - something, something",age,sex,,,,"name, brand - something, something, something",,,,,

Precisa ser convertido para:

12,name; brand - something; something,age,sex,,,,name; brand - something; something; something,,,,,

Como você pode ver, substituí as ,aspas duplas internas por ;para que quando eu carregar o arquivo no MySQL as ,aspas duplas internas não sejam consideradas um separador, pois não são ,mais. Também removi as aspas duplas "porque não são necessárias.

Tentei automatizar isso para cada linha do meu arquivo CSV usando sed da seguinte maneira:

sed -e 's/"\*,\*"/"\*;\*"/g' -e 's/"//g' input.csv > output.csv

Mas o resultado não substituiu o ,que vem entre aspas duplas por ;. Apenas removeu as aspas duplas:

12,name, brand - something, something,age,sex,,,,name, brand - something, something, something,,,,,

Responder1

csv podem ser muito complicados. Você pode acabar tendo uma aspa de escape em algum lugar da linha e a expressão regular para lidar com isso seria ilegível e propensa a erros.

Eu sugeriria uma ferramenta comocvskitou um pequeno script em perl ou python. Este programa criado rapidamente em python deve servir:

import csv

with open('input.csv',mode='r') as csv_file:
   csv_reader = csv.reader(csv_file)
   for row in csv_reader:
       print (',').join([f.replace(',',';') for f in row])

Responder2

Como já mencionado por @steeldriver, mysqlprovavelmente sabe como lidar com isso se usar oopções certas, mas FWIW você pode fazer isso com o awk:

awk -v RS='"' -v ORS= 'NR % 2 || gsub(/,/,";") || 1'

12,name; brand - something; something,age,sex,,,,name; brand - something; something; something,,,,,

Ou, mantendo as aspas anexas:

awk -v RS='"' -v ORS= '{if(NR % 2) print; else{gsub(/,/,";");print RS $0 RS}}'

12,"name; brand - something; something",age,sex,,,,"name; brand - something; something; something",,,,,

Isso está usando o mesmo truque queaqui, apenas revertido: em vez de modificar a peçaforaas aspas, estou modificando a partedentroas citações.

Responder3

A melhor resposta que encontrei é usar o próprio MySQL adicionando esta linha:

OPTIONALLY ENCLOSED BY '"'

Por exemplo, a consulta de carregamento é assim:

LOAD DATA INFILE 'filename.csv' INTO TABLE table_name 
  FIELDS TERMINATED BY ',' 
  OPTIONALLY ENCLOSED BY '"'
  IGNORE 1 LINES;

informação relacionada