如何删除 CSV 文件中特定列中的换行符?

如何删除 CSV 文件中特定列中的换行符?

我有一个包含 150 多列的 CSV 文件,其中使用换行符作为记录分隔符。问题在于其中一列获得换行符。为此,我想删除这些。

输入:

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

答案1

sed只要当前行不包含 4 个|字符,您就可以将下一行合并到当前行中:

<file sed -e :1 -e 's/|/|/4;t' -e 'N;s/\n/ /;b1'

某些sed实现具有-i-i ''可以就地编辑文件(-i.back以使用扩展名保存原始文件.back),因此使用这些实现,您可以执行以下操作:

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

编辑csv当前目录下的所有非隐藏文件。

与评论相同:

<file sed '
   :1
     s/|/|/4; # replace the 4th | with itself. Only useful when combined with
              # the next "t" command which branches off if the previous
              # substitution was successful
     t
     # we only reach this point if "t" above did not branch off, that is
     # if the pattern space does not contain 4 "|"s
     N; # append the next line to the pattern space
     s/\n/ /; # replace the newline with a space

   # and then loop again in case the pattern space still does not contain
   # 4 "|"s:
   b1'

答案2

依赖于第一个字段的格式(假设每行应以数字开头):

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

答案3

另一个 GNUawk解决方案依赖于|每条记录 4 次:

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

RS设置为记录包含 4 个分隔符(即使有换行符)。

RT追上了 所创造的记录RSgsub删除记录上的换行符。

答案4

如果我们可以假设任何只有 2 个字段的行都应该删除其尾随换行符,则可以在 Perl 中执行以下操作:

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

重要免责声明:正如 Stéphane Chazelas 的评论中所指出的,这假设您的输入不包含任何%字符,因为如果包含任何字符,这些字符将被视为 的格式说明符printf。这可能会产生意想不到的后果,从简单地打印错误的输出到吃东西负载RAM,如果你的输入有一些愚蠢的东西,比如%02147483600f%02147483600f%02147483600f%02147483600f.

解释

  • -a: 使perl行为类似于awk,在给定的字符上分割每个输入行-F(因此,|这里是 a;需要转义,因为\|因为|在 perl 正则表达式中意味着 OR)并将结果保存为数组@F
  • -l:这会从每个输入行中删除尾随换行符,并'n在每次调用时添加一个 t print
  • -ne:逐行读取输入文件并将给定的脚本应用于-e每一行。
  • $#F==1 ? printf : print'$#F变量是数组中元素的数量@F,即字段的数量。因此,这意味着如果字段数为 1,则printf(这将打印当前行而不带换行符,因为现有行已被删除-l并且printf不会添加一个)。如果字段数不正好为 1,print则该行(因为-l将添加换行符)。

同样的事情可以扩展到:

$ perl -e 'while($line=<STDIN>){
            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'

相关内容