[英]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'
它复制了上一个命令并使用了;
在g
和s
之间切断它们。 或者,您可以为每个搜索表达式使用-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
概念:
;
;
在行尾之前最终有空间 这可能适合你(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.