Чтобы смочь импортировать некоторые данные в определенный инструмент, я должен преобразовать файл CSV от этого формата
"data","data","data data","data","123"
в этот формат
data;data;data data;data;123
Столбцы никогда не содержат никого "
, ;
или ,
но могут быть пробелы. В настоящее время я использую следующее
sed -e 's/","/;/g' -e 's/"//g' input.csv > output.csv
Хотя это хорошо работает, интересно, может ли это быть сделано более изящно, т.е.
Спасибо за Ваш вход!
( tr , ';' | tr -d '"' ) < input.csv > output.csv
Я использовал бы Perl
perl -pe 'tr/,"/;/d' input.csv > output.csv
- но эта определенная задача не вне sed. Вы не можете объединить эти два выражения.
Который Вы предпочитаете (жемчуг, sed, awk) ваше дело; они все сделают задание. Так как Вы попросили sed, и другие отправляются, здесь Вы идете. Это - более простая форма Вашего regex's и работает с Вашей строкой в качестве примера:
$ 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
Я довольно уверен, что возможно объединить эти две замены. Не уверенный, что это было бы пренебрежительно, и я вполне уверен, результат будет намного менее читаем, чем сценарий наверху. Если я придумаю что-то (или кто-то еще взвешивается в комментариях), то я добавлю его здесь.
Так как Вы имеете дело с записями, awk
имеет больше смысла. Тем не менее это не действительно хорошо в CSV, так как разделители полей являются несколько переменными. Но если Вы будете уверены, что все поля окружаются doublequotes, то это будет работать:
awk -F'","' 'BEGIN {OFS=";"} { gsub(/(^")|("$)/, ""); $1=$1; print }'
Это устанавливает разделитель поля ввода awk на"","
"(включая внутренний набор doublequotes). Это почти работает, кроме Вас должны иметь дело с продвижением и запаздыванием doublequotes, которые разделяются с gsub
функция. $1=$1
силы это для перекомпиляции записи с новым выходным разделителем полей, который был определен как ;
в НАЧАТЬ блоке. Затем print
распечатывает целую запись.
Это немного более опрятно:
awk -F '(^")|(",")|("$)' 'BEGIN {OFS=";"} { $1=$1; print }'
Это устанавливает разделитель поля ввода на регулярное выражение, которое включает doublequotes вначале и конец записи, но это также заставляет это распечатывать пустое начало и запаздывающее поле. Можно легко избавиться от запаздывающего поля:
awk -F '(^")|(",")|("$)' 'BEGIN {OFS=";"} { NF=NF-1; $1=$1; print }'
NF
количество полей и сокращение его, каждый сокращает последнее поле. Но я не могу думать о способе обрубить первое поле.
Если Вы знаете, что вход всегда имеет пять полей, тем не менее, Вы могли сделать это:
awk -F '(^")|(",")|("$)' 'BEGIN {OFS=";"} { print $2,$3,$4,$5,$6 }'
Заметьте, что это избавляется от $1=$1
создайте, в котором мы только нуждаемся, если мы печатаем (подразумеваемые) 0$.
Однако я, вероятно, закончил бы тем, что использовал жемчуг и один из многих доступных модулей CSV на CPAN.