繁体   English   中英

使用sed处理带分隔符的文本文件

[英]process a delimited text file with sed

我有一个 ”;” 分隔文件:

aa;;;;aa
rgg;;;;fdg
aff;sfg;;;fasg
sfaf;sdfas;;;           
ASFGF;;;;fasg
QFA;DSGS;;DSFAG;fagf

我想处理它用\\N替换缺失值。 结果应该是:

aa;\N;\N;\N;aa
rgg;\N;\N;\N;fdg
aff;sfg;\N;\N;fasg
sfaf;sdfas;\N;\N;\N         
ASFGF;\N;\N;\N;fasg
QFA;DSGS;\N;DSFAG;fagf

我正在尝试使用sed脚本:

sed "s/;\(;\)/;\\N\1/g" file1.txt  >file2.txt

但我得到的是

aa;\N;;\N;aa
rgg;\N;;\N;fdg
aff;sfg;\N;;fasg
sfaf;sdfas;\N;;         
ASFGF;\N;;\N;fasg
QFA;DSGS;\N;DSFAG;fagf

您不需要将第二个分号括在括号中,只是在替换字符串中将其用作\\1 你可以用; 在替换字符串中:

sed 's/;;/;\\N;/g'

正如您所注意到的,当它找到一对分号时,它会用所需的字符串替换它,然后跳过它,而不是再次读取第二个分号,这使得它在每两个分号后插入\\N

一个解决方案是使用积极的前瞻; regex/;(?=;)/但是sed不支持它们。

但是可以通过简单的方式使用sed解决问题:复制搜索命令; 第一个命令取代奇怪的外观;; ;\\N ,第二个照顾均匀的外观。 最终的结果是你需要的。

命令很简单:

sed 's/;;/;\\N;/g;s/;;/;\\N;/g'

它复制了上一个命令并使用了; gs之间切断它们。 或者,您可以为每个搜索表达式使用-e命令行选项一次:

sed -e 's/;;/;\\N;/g' -e 's/;;/;\\N;/g'

更新:

OP在评论中询问“如果我的文件有100列怎么办?”

让我们试试看它是否有效:

$ echo "0;1;;2;;;3;;;;4;;;;;5;;;;;;6;;;;;;;" | sed 's/;;/;\\N;/g;s/;;/;\\N;/g'
0;1;\N;2;\N;\N;3;\N;\N;\N;4;\N;\N;\N;\N;5;\N;\N;\N;\N;\N;6;\N;\N;\N;\N;\N;\N;

看,妈! 有用! :-)


更新#2

我忽略了这个问题没有要求更换的事实;; 使用其他东西,但要替换使用的文件中的空/缺少值; 分隔列。 因此,当表达式出现在行的开头或结尾时,我的表达式不会修复缺失值。

正如OP在评论中添加的那样,完整的sed命令是:

sed 's/;;/;\\N;/g;s/;;/;\\N;/g;s/^;/\\N;/g;s/;$/;\\N/g'

或(为了便于阅读):

sed -e 's/;;/;\\N;/g;' -e 's/;;/;\\N;/g;' -e 's/^;/\\N;/g' -e 's/;$/;\\N/g'

另外两个步骤取代';' 当他们在开始或结束时找到它。

您可以将此sed命令与2 s (替换)命令一起使用:

sed 's/;;/;\\N;/g; s/;;/;\\N;/g;' file
aa;\N;\N;\N;aa
rgg;\N;\N;\N;fdg
aff;sfg;\N;\N;fasg
sfaf;sdfas;\N;\N;
ASFGF;\N;\N;\N;fasg
QFA;DSGS;\N;DSFAG;fagf

或者在perl命令中使用lookarounds regex

perl -pe 's/(?<=;)(?=;)/\\N/g' file
aa;\N;\N;\N;aa
rgg;\N;\N;\N;fdg
aff;sfg;\N;\N;fasg
sfaf;sdfas;\N;\N;
ASFGF;\N;\N;\N;fasg
QFA;DSGS;\N;DSFAG;fagf

主要问题是,对于单个替换,您不能使用多次相同的字符:

s/;;/..../g :第二个; 不能在字符串中的下一个匹配中重复使用;;;

如果你想使用sed而不使用类似Perl的正则表达式模式,你可以使用带有条件命令t的循环:

sed ':a;s/;;/;\\N;/g;ta;' file

:a定义了一个标签“一”, ta去只有当事情已被替换这个标签。

对于; 在行尾(并处理最终的尾随空格):

sed ':a;s/;;/;\\N;/g;ta; s/;[ \t\r]*$/;\\N/1' file

这个awk one-liner会给你你想要的东西:

awk -F';' -v OFS=';' '{for(i=1;i<=NF;i++)if($i=="")$i="\\N"}7' file

如果你真的想要这一行: sfaf;sdfas;\\N;\\N;\\N ,这行适用于你:

awk -F';' -v OFS=';' '{for(i=1;i<=NF;i++)if($i=="")$i="\\N";sub(/;$/,";\\N")}7' file
sed 's/;/;\\N/g;s/;\\N\([^;]\)/;\1/g;s/;[[:blank:]]*$/;\\N/' YourFile
  • 非递归,在线,posix兼容

概念:

  • 改变一切;
  • 放回无与伦比的
  • 添加最后一个特例; 在行尾之前最终有空间

这可能适合你(GNU sed):

sed -r ':;s/^(;)|(;);|(;)$/\2\3\\N\1\2/g;t' file

有4个可能出现空字段的情况:在记录的开头,2个字段分隔符之间,空字段后面的空字段和记录的结尾。 可以采用轮换来满足上述情况1,2和4,并且可以使用循环( :;...;t )通过第二次传递来满足senario 3。 使用g标志可以在两次传递中替换多个senarios。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM