7

Чтобы иметь возможность импортировать некоторые данные в определенный инструмент, мне нужно преобразовать файл CSV из этого формата.

"data","data","data data","data","123"

в этот формат

data;data;data data;data;123

Столбцы никогда не содержат каких - либо " ; но могут быть пробелы. В настоящее время я использую следующее

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

Хотя это прекрасно работает, мне интересно, если это можно сделать более элегантно, то есть

  • Является ли sed правильным (стандартным Unix) инструментом для работы?
  • Можно ли объединить оба выражения в одно?

Спасибо за ваш вклад!

3 ответа3

6
( tr , ';' | tr -d '"' ) < input.csv > output.csv

Я бы использовал Perl

perl -pe 'tr/,"/;/d' input.csv > output.csv

- но эта конкретная задача не выходит за рамки SED. Вы не можете объединить два выражения.

5

Что вы предпочитаете (perl, sed, awk), зависит от вас; они все сделают работу. Так как вы попросили sed, а остальные опубликованы, вот и вы. Это более простая форма вашего регулярного выражения и работает с вашей строкой примера:

$ sed -e 's/"//g; s/,/;/g' infile.csv > outfile.csv

Обратите внимание, что вы можете объединить два выражения с точкой с запятой после каждой замены. Протестировано с GNU sed v4.1.5.

Вот ваши оригинальные выражения присоединились:

$ sed -e 's/","/;/g; s/"//g' infile.csv > outfile.csv

Я вполне уверен, что возможно объединить две замены. Не уверен, что это было бы не так, и я уверен, что результат будет гораздо менее читабельным, чем сценарий вверху. Если я что-то придумаю (или кто-то еще взвешивает в комментариях), я добавлю это сюда.

4

Поскольку вы имеете дело с записями, awk имеет больше смысла. Тем не менее, это не очень хорошо в CSV, так как разделители полей несколько изменчивы. Но если вы уверены, что все поля заключены в двойные кавычки, это будет работать:

awk -F'","' 'BEGIN {OFS=";"} { gsub(/(^")|("$)/, ""); $1=$1; print }'

Это устанавливает разделитель входного поля в awk на " "," " (включая внутренний набор двойных кавычек). Это почти работает, за исключением того, что вам приходится иметь дело с ведущими и конечными двойными кавычками, которые удаляются с помощью функции gsub . $1=$1 заставляет его перекомпилировать запись с новым разделителем выходного поля, который был определен как ; в блоке BEGIN. Затем print распечатайте всю запись.

Это немного аккуратнее:

awk -F '(^")|(",")|("$)' 'BEGIN {OFS=";"} { $1=$1; print }'

Он устанавливает в качестве разделителя поля ввода регулярное выражение, которое включает в себя двойные кавычки в начале и конце записи, но также заставляет его печатать пустое поле начала и конца поля. Вы можете легко избавиться от конечного поля:

awk -F '(^")|(",")|("$)' 'BEGIN {OFS=";"} { NF=NF-1; $1=$1; print }'

NF - это число полей, и уменьшение его на единицу отрывает от последнего поля. Но я не могу придумать, как отрубить первое поле.

Если вы знаете, что у ввода всегда есть пять полей, вы можете сделать это:

awk -F '(^")|(",")|("$)' 'BEGIN {OFS=";"} { print $2,$3,$4,$5,$6 }'

Обратите внимание, что это избавляет от конструкции $1=$1 , которая нам нужна, только если мы печатаем (подразумевается) $ 0.

Все это говорит о том, что я, вероятно, в конечном итоге использовал Perl и один из многих доступных модулей CSV на CPAN.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .