过滤文本文件以删除空行的好方法是什么?


11

我有一个.csv文件(在Mac上),有一堆空行,例如:

"1", "2", "lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum 

lorem ipsum ","2","3","4"
"1", "2", "lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum 

lorem ipsum ","2","3","4"

我想转换为:

"1", "2", "lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum ","2","3","4"
"1", "2", "lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum  lorem ipsum ","2","3","4"

我知道必须有一个班轮,但我不知道awk或sed。任何提示,不胜感激!


1
根据该示例,您实际上要从字段中删除嵌入的换行符。那是对的吗?换句话说,有6条输入线,应该有2条输出线吗?
manatwork 2012年

是的,这正是我要摆脱的东西:在带引号的字符串中嵌入换行符。
pitosalas 2012年

因此,您需要的是删除引号内换行符的东西。这将稍微复杂一点,因为您需要多行正则表达式。
tongpu

Answers:


11

您可以使用grep的-v(反向匹配)模式来执行此操作:

grep -v '^$' old-file.csv > new-file.csv

请注意,由于shell重定向的工作原理,这些文件必须是不同的文件。在读取输入文件之前,将打开(并清空)输出文件。如果您有moreutils(在Mac OS X上不是默认值),则可以使用sponge此方法来解决此问题:

grep -v '^$' file.csv | sponge file.csv

但是,当然,如果出现问题,您将很难回头。

如果“空白行”实际上可能包含空格(听起来像它们一样),则可以改用以下方式:

egrep -v '^[[:space:]]*$' old-file.csv > new-file.csv

这将忽略空白行以及仅包含空格的行。您当然可以对其进行相同的sponge转换。


谢谢...。没有删除任何空行...也许^ $不匹配?但据我所知,这些行是空的。记住这是excel在Mac上创建的cdv。(不要逃避尖叫,因为我说过Excel :)
pitosalas 2012年

@pitosalas他们可能不是空行。尝试将其更改为egrep -v '^[[:space:]]*$'...注意grep-> egrep和奇怪的新模式
derobert 2012年

没有工作。删除了一堆双引号并弄得一团糟...
pitosalas 2012年

@pitosalas我不确定如何删除双引号。它只能删除空白。确实,这就是我在您发布的示例数据上对其进行测试时所做的……
derobert 2012年

@pitosalas你能不能检查,如果这些命令吐出来的东西看起来是合理的(而不是乱码):iconv -f utf16le file.csv | headiconv -f utf16be file.csv | head
derobert

8

最简单的选择是grep .。在这里,点表示“匹配所有内容”,因此如果该行为空,则表示不匹配。否则它将按原样打印整行。


6

要删除空行,到位,与ksh93的:

sed '/./!d' file 1<>; file

所述<>;重定向操作器是专用于ksh93的和是相同的标准<>,除了ksh的截断命令之后的文件已经终止操作。

sed '/./!d'是一种复杂的写法grep .,但是不幸的是,如果它的stdout指向与其stdin相同的文件,则GNU grep至少会抱怨。您可能会说:

grep . file | cat 1<>; file

但是不幸的是,ksh93中存在一个错误(至少是我的版本(93u +)),在这种情况下文件似乎被截断为零长度。

grep . file | { cat; } 1<>; file

似乎可以解决该错误,但是现在,它比sed命令复杂得多。


请将您的答案合并到一个格式正确的条目中,并提供有关何时应采用每种解决方案的快速指南。所有针对不同问题的不同方法都以浮动答案混杂在一起,这使这个问题难以理解。
Caleb

@Caleb,这全都归结为非常不清楚的问题,因此每个人的答案都是对该问题的不同解释。对于每个答案,我都试图说出它试图回答哪个问题。
斯特凡Chazelas

仅供参考:试过了awk '/./' file 1<>; file。对我来说,这比sed '/./!d'
grebneke

5

这是Perl一线的:

perl -pi -e 's/^\s*\n//' yourfile

编辑:基于以下ruakh的注释改进的代码。


1
perl -ni -e '/./ and print' yourfile
derobert

1
@peterph $是锚点(即零宽度),因此它不包含换行符。至于多余的空间,这就是我添加的原因,我/x不想Perl尝试在正则表达式中插入“ $ \”
Joseph R.

1
$鉴于您拥有,您不需要\n。(或者- \n考虑到您具有\s*和,因此您不需要- $,但是我想s/^\s*\n//更清楚地删除了换行符。)您也不需要/m; 它对此命令没有影响。而一旦您摆脱了$和空间,您将不需要/x
ruakh

1
@JosephR .:\n本身可以删除;你不能做的是删除这两个$ \n。因此s/^\s*//会有您所描述的问题,但s/^\s*$//会很好,因为\s*$。(你明白我的意思吗?)
ruakh

1
@JosephR:发生了什么,$ 可以换行前相匹配(前提是无论是/m标志被允许,或者换行符是字符串的最后一个字符,或两者),但它匹配字符串的结尾。例如,"abc" =~ m/^abc$/是真的。在的情况下\s*$,的\s*贪婪足以吃掉换行符,然后$匹配字符串末尾。(但是s/^\s*\n//无论如何,我认为更清晰,所以您的回答现在还是很好。)
ruakh 2012年

5

根据对问题的评论中的澄清,类似:

awk -v RS= -v ORS= 1

可以做你想要的。

记录分隔符是一种特殊情况,它告诉awk记录将成为段落(由空行序列分隔)。将输出记录分隔符设置为空字符串也意味着这些段落(不包含分隔符)的内容将被串联。1只是打印每条记录的真实条件。

但是,这将忽略结尾的换行符,因此您可以执行以下操作:

awk -v RS= -v ORS= '1;END{if (NR) printf "\n"}'

3

我知道如果我提供文件会更容易,但是不幸的是它包含了我无法共享的机密信息。同时,我给我写了一个红宝石脚本,似乎可以解决问题:

require 'csv'
c = CSV.open("outfile1.csv", "w")
CSV.foreach("data.csv", :encoding => 'windows-1251:utf-8') do |row|
  row = row.map { |a| a.class == String ? a.gsub(/\r/, '') : a}
  c << row
end
c.close

谢谢大家的帮助!


2
awk '
    length == 0 {next} 
    /^[^"]/ && /"$/ {print; next} 
    {printf("%s", $0)}
' filename

产生

"1", "2", "lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum ","2","3","4"
"1", "2", "lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum ","2","3","4"

2

我找到了一个关于stackoverflow的可能解决方案的想法。

sed -i ':a;N;$!ba;s/[^"]\n\s*\n/ /g' file.csv

您可能应该在测试之前先备份csv文件,但是至少对于您提供的示例而言,它可以完美地工作。

答案中提供了有关此表达式的内部工作原理的很好的解释,我只是对其进行了编辑以查找不以"[^"]\n)结尾的行。


1

如果要从您自己的响应中删除引号字符串中包含的换行符,则可以执行以下操作:

 perl -0777 -pe 's/".*?"/$_=$&;s:\n::g;$_/gse'

您还可以使用use perl的-i标志在适当位置编辑文件。

 perl -0777 -pe 's/".*?"/$_=$&;s:\n::g;$_/gse' file1 file2...

或使用GNU awk:

 awk -v RS=\" 'NR%2==0 {gsub("\n","")}; {printf "%s", $0 RT}'

要么:

 awk -vRS=\" '1-NR%2{gsub("\n","")}{ORS=RT}1'

(如果您要竞争最短的)

请注意,那些假定输入中没有转义的双引号字符。


0

实际上,您想要的不仅仅是删除空行,而是删除2个或更多换行符的每个序列。

您可以使用perl进行以下操作:

perl -0777 -pe 's/\n{2,}//gs' file

您还可以使用use perl的-i标志在适当位置编辑文件。

perl -0777 -pi -e 's/\n{2,}//gs' file1 file2...

0

删除空行的方法越来越短AWK

awk 'NF' file

但是要获得所需的输出,只需要一个简单的衬板即可:

awk 'NF {printf("%s ", $0); i++;} !(i % 2) {printf("\n");}' file

说明

在中AWK,空行表示行/记录中没有字段,即NF(Number of Fields)变量为零。上面的一个衬纸仅在NF > 0打印所有行时执行,但打印空行。

i++是非空行柜台。

!(i % 2)是为了在你想要的输出,即的方法来打印两个连续的非空行中,每2的倍数被发现时,modulo声明!(i % 2)产量1,什么结束的两个非空行的连接。


我的错!抱歉。我没有阅读他的整个问题和所需的输出。现在答复已修复。谢谢。:-)
马塞洛·奥古斯托

0

您可以在Ex模式下使用Vim:

ex -sc v/./d -cx b.csv
  1. v/./ 找到空行

  2. d 删除

  3. x 保存并关闭

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.