Как удалить символ новой строки в определенном столбце в файле CSV?

У меня есть CSV-файл с 150+ столбцами, с символом новой строки в качестве разделителя записей Проблема заключается в том, что в одном из столбцов появляются символы новой строки. Для этого я хочу удалить их.

Входные данные:

001|Baker St. London|3|4|7 002|Penny Lane Liverpool|88|5|7 

Выход:

 001|Baker St. London|3|4|7 002|Penny Lane Liverpool|88|5|7 

Вы можете использовать sed чтобы объединить следующую строку с текущей, если текущая строка не содержит 4 | персонажи:

  

В некоторых реализациях sed есть -i или -i '' для редактирования файлов на месте ( -i.back для сохранения оригинала с расширением .back ), поэтому с ними вы можете сделать:

 sed -i -e :1 -e 's/|/|/4;t' -e 'N;s/\n/ /;b1' ./*.csv 

Для редактирования всех не скрытых файлов csv в текущем каталоге.

То же самое с комментариями:

  

Опираясь на формат первого поля (при условии, что каждая строка должна начинаться с цифры):

 awk 'NR == 1{ printf $0; next } { printf "%s%s", (/^[0-9]+/? ORS : ""), $0 } END{ print "" }' file.csv 

Выход:

 001|Baker St.London|3|4|7 002|Penny LaneLiverpool|88|5|7 

Еще одно решение GNU awk 4 раза | за запись:

 awk -v RS='([^|]+\\|){4}[^|]+\n' '{gsub(/\n/," ",RT); print RT}' file 

RS устанавливается так, что запись содержит 4 разделителя (даже с новой строкой).

RT ловит рекорд, установленный RS . gsub удаляет новую строку в записи.

Если мы можем предположить, что у любой строки, содержащей только 2 поля, должен быть удален завершающий символ новой строки, вы можете сделать следующее в Perl:

 $ perl -F"\|" -lane '$#F==1 ? printf : print' file.csv 001|Baker St.London|3|4|7 002|Penny LaneLiverpool|88|5|7 

Важный отказ от ответственности : как отмечено в комментариях Стефана Шазеля, это предполагает, что ваш ввод не содержит символов % так как, если это произойдет, они будут приняты как спецификатор формата для printf . Это может привести к непреднамеренным последствиям, начиная от простой распечатки неправильных %02147483600f%02147483600f%02147483600f%02147483600f ОЗУ, если ваш ввод имеет что-то глупое, например %02147483600f%02147483600f%02147483600f%02147483600f .

объяснение

  • -a : заставляет perl действовать как awk , разбивая каждую строку ввода на символ, заданный -F (так, здесь | , который должен быть экранирован как \| поскольку | означает регулярные выражения perl) и сохраняя результат как массив @F .
  • -l : удаляет завершающие символы новой строки из каждой строки ввода и добавляет не каждый вызов print .
  • -ne : построчно читать входной файл и применять скрипт, заданный -e к каждой строке.
  • $#F==1 ? printf : print' $#F==1 ? printf : print' : переменная $#F – это количество элементов в массиве @F , то есть количество полей. Следовательно, это означает, что если количество полей равно 1, то printf (который будет печатать текущую строку без символа новой строки, поскольку существующая была удалена с помощью -l а printf не добавляет одно). Если количество полей не точно 1, print строку (которая из-за -l добавит новую строку).

То же самое можно расширить до:

 $ perl -e 'while($line=){ chomp $line; @fields=split(/\|/,$line); if(scalar(@fields) == 2){ print "$line"; } else{ print "$line\n" } }' < file.csv 001|Baker St.London|3|4|7 002|Penny LaneLiverpool|88|5|7 

И еще более короткая версия, предложенная @Sundeep в комментариях:

 perl -F'\|' -ape 'chomp if $#F==1' 

если первая строка вашего CSV верна, будет работать следующий код.

 awk 'NR==1{printf "%s",$0; gsub(/[^|]/,""); nlast=n=length($0); next;} nlast==n{printf "\n";nlast=0} {printf "%s",$0; gsub(/[^|]/,""); nlast+=length($0)} END{print ""}' file_201805072030.csv > temp.csv && mv -f temp.csv file_201805072030.csv 

если ни одна из строк не является правильной, и если вы хотите переставить с 5 столбцами

 awk 'NR==1{printf "%s",$0; gsub(/[^|]/,""); nlast=n=4; next;} nlast==n{printf "\n";nlast=0} {printf "%s",$0; gsub(/[^|]/,""); nlast+=length($0)} END{print ""}' file_201805072030.csv > temp.csv && mv -f temp.csv file_201805072030.csv 

С помощью инструмента sed вы можете сделать следующее:

 sed -i -e ' /^\(\([^|]*|\)\{2\}\)*[^|]*$/b N;s/\n/ / s/^/\n/;D ' . /*.csv 

Объяснение:

  1. Переход к концу обработки кода sed для текущих данных пространства шаблонов при обнаружении четного числа каналов.

  2. Или перейдите к следующей строке и добавьте ее в пространство шаблона.

  3. Теперь снова примените код sed в пространстве шаблонов.

      perl -i.BAK -lpe ' $\ = ( $k += tr/|/|/ ) =~ /[24680]$/ ? "\n" : " "; ' . /*.csv 
  4. $k – это текущий счетчик числа, если трубы видны в любое время.

  5. Даже если мы печатаем с новой строки, в противном случае мы соединяем строки с пробелом.

 awk '/Baker/{printf "%s ",$0; getline; printf "%s\n", $0} \ /Penny/{printf $0; getline; printf "%s\n", $0}' file 001|Baker St. London|3|4|7 002|Penny LaneLiverpool|88|5|7