从 csv 文件中仅删除*一些*句号
remove only *some* fullstops from a csv file
如果我有如下行:
1,987372,987372,C,T,.,.,.,.,.,.,.,.,1,D,.,.,.,.,.,.,.,1.293,12.23,0.989,0.973,D,.,.,.,.,0.253,0,4.08,0.917,1.048,1.000,1.000,12.998
1,987393,987393,C,T,.,.,.,.,.,.,.,.,1,D,.,.,.,.,.,.,0.152,1.980,16.09,0.999,0.982,D,-0.493,T,0.335,T,0.696,0,5.06,0.871,0.935,0.998,0.997,16.252
如何将 ,.,
的所有实例替换为 ,?,
我想保留数字中的实际小数位,所以我不能这样做
sed 's/./?/g' file
但是在做的时候:
sed 's/,.,/,?,/g' file
这似乎只在某些情况下有效。即仍然有 ,.,
的实例徘徊。
有人有什么指点吗?
谢谢
这应该有效:
sed ':a;s/,\.,/,?,/g;ta' file
对于连续的 ,.,
字符串,在替换成功后,下一个要处理的字符将是以下 .
与模式不匹配的字符,因此您需要第二遍。
:a
是即将到来的循环的标签
,\.,
将匹配逗号之间的点。请注意,必须转义点,因为 .
用于匹配任何字符(,a,
将匹配 ,.,
)。
g
用于一般替换
ta
测试先前的替换,如果成功,则循环到 :a
标签以进行剩余替换。
使用 sed 可以通过 运行 一个循环,如上面的答案所示,但是使用 perl
带有环顾四周的命令行很容易解决问题:
perl -pe 's/(?<=,)\.(?=,)/?/g' file
1,987372,987372,C,T,?,?,?,?,?,?,?,?,1,D,?,?,?,?,?,?,?,1.293,12.23,0.989,0.973,D,?,?,?,?,0.253,0,4.08,0.917,1.048,1.000,1.000,12.998
1,987393,987393,C,T,?,?,?,?,?,?,?,?,1,D,?,?,?,?,?,?,0.152,1.980,16.09,0.999,0.982,D,-0.493,T,0.335,T,0.696,0,5.06,0.871,0.935,0.998,0.997,16.252
此命令不需要循环,因为我们不匹配周围的逗号,而是使用后向和前向来断言它们的位置。
您有一个使用 sed
样式正则表达式的示例。我将提供一个替代方案 - 解析 CSV,然后将每件事视为 'field':
#!/usr/bin/perl
use strict;
use warnings;
#iterate input row by row
while ( <DATA> ) {
#remove linefeeds
chomp;
#split this row on ,
my @row = split /,/;
#iterate each field
foreach my $field ( @row ) {
#replace this field with "?" if it's "."
$field = "?" if $field eq ".";
}
#stick this row together again.
print join ",", @row,"\n";
}
__DATA__
1,987372,987372,C,T,.,.,.,.,.,.,.,.,1,D,.,.,.,.,.,.,.,1.293,12.23,0.989,0.973,D,.,.,.,.,0.253,0,4.08,0.917,1.048,1.000,1.000,12.998
1,987393,987393,C,T,.,.,.,.,.,.,.,.,1,D,.,.,.,.,.,.,0.152,1.980,16.09,0.999,0.982,D,-0.493,T,0.335,T,0.696,0,5.06,0.871,0.935,0.998,0.997,16.252
为了说明这个概念,这比需要的更冗长。这可以减少到:
perl -F, -lane 'print join ",", map { $_ eq "." ? "?" : $_ } @F'
如果您的 CSV 也有引号,那么您可以打开 Text::CSV
模块,它可以巧妙地处理这个问题。
只需要一次替换
$ perl -pe 's/,\.(?=,)/,?/g' dots.csv
1,987372,987372,C,T,?,?,?,?,?,?,?,?,1,D,?,?,?,?,?,?,?,1.293,12.23,0.989,0.973,D,?,?,?,?,0.253,0,4.08,0.917,1.048,1.000,1.000,12.998
1,987393,987393,C,T,?,?,?,?,?,?,?,?,1,D,?,?,?,?,?,?,0.152,1.980,16.09,0.999,0.982,D,-0.493,T,0.335,T,0.696,0,5.06,0.871,0.935,0.998,0.997,16.252
您只需要 2 遍,因为在 ,.,
匹配中找到的尾随 ,
无法匹配下一个 ,.,
中的前导 ,
:
$ sed 's/,\.,/,?,/g; s/,\.,/,?,/g' file
1,987372,987372,C,T,?,?,?,?,?,?,?,?,1,D,?,?,?,?,?,?,?,1.293,12.23,0.989,0.973,D,?,?,?,?,0.253,0,4.08,0.917,1.048,1.000,1.000,12.998
1,987393,987393,C,T,?,?,?,?,?,?,?,?,1,D,?,?,?,?,?,?,0.152,1.980,16.09,0.999,0.982,D,-0.493,T,0.335,T,0.696,0,5.06,0.871,0.935,0.998,0.997,16.252
以上将在任何 OS 上的任何 sed 中工作。
如果我有如下行:
1,987372,987372,C,T,.,.,.,.,.,.,.,.,1,D,.,.,.,.,.,.,.,1.293,12.23,0.989,0.973,D,.,.,.,.,0.253,0,4.08,0.917,1.048,1.000,1.000,12.998
1,987393,987393,C,T,.,.,.,.,.,.,.,.,1,D,.,.,.,.,.,.,0.152,1.980,16.09,0.999,0.982,D,-0.493,T,0.335,T,0.696,0,5.06,0.871,0.935,0.998,0.997,16.252
如何将 ,.,
的所有实例替换为 ,?,
我想保留数字中的实际小数位,所以我不能这样做
sed 's/./?/g' file
但是在做的时候:
sed 's/,.,/,?,/g' file
这似乎只在某些情况下有效。即仍然有 ,.,
的实例徘徊。
有人有什么指点吗?
谢谢
这应该有效:
sed ':a;s/,\.,/,?,/g;ta' file
对于连续的 ,.,
字符串,在替换成功后,下一个要处理的字符将是以下 .
与模式不匹配的字符,因此您需要第二遍。
:a
是即将到来的循环的标签
,\.,
将匹配逗号之间的点。请注意,必须转义点,因为 .
用于匹配任何字符(,a,
将匹配 ,.,
)。
g
用于一般替换
ta
测试先前的替换,如果成功,则循环到 :a
标签以进行剩余替换。
使用 sed 可以通过 运行 一个循环,如上面的答案所示,但是使用 perl
带有环顾四周的命令行很容易解决问题:
perl -pe 's/(?<=,)\.(?=,)/?/g' file
1,987372,987372,C,T,?,?,?,?,?,?,?,?,1,D,?,?,?,?,?,?,?,1.293,12.23,0.989,0.973,D,?,?,?,?,0.253,0,4.08,0.917,1.048,1.000,1.000,12.998
1,987393,987393,C,T,?,?,?,?,?,?,?,?,1,D,?,?,?,?,?,?,0.152,1.980,16.09,0.999,0.982,D,-0.493,T,0.335,T,0.696,0,5.06,0.871,0.935,0.998,0.997,16.252
此命令不需要循环,因为我们不匹配周围的逗号,而是使用后向和前向来断言它们的位置。
您有一个使用 sed
样式正则表达式的示例。我将提供一个替代方案 - 解析 CSV,然后将每件事视为 'field':
#!/usr/bin/perl
use strict;
use warnings;
#iterate input row by row
while ( <DATA> ) {
#remove linefeeds
chomp;
#split this row on ,
my @row = split /,/;
#iterate each field
foreach my $field ( @row ) {
#replace this field with "?" if it's "."
$field = "?" if $field eq ".";
}
#stick this row together again.
print join ",", @row,"\n";
}
__DATA__
1,987372,987372,C,T,.,.,.,.,.,.,.,.,1,D,.,.,.,.,.,.,.,1.293,12.23,0.989,0.973,D,.,.,.,.,0.253,0,4.08,0.917,1.048,1.000,1.000,12.998
1,987393,987393,C,T,.,.,.,.,.,.,.,.,1,D,.,.,.,.,.,.,0.152,1.980,16.09,0.999,0.982,D,-0.493,T,0.335,T,0.696,0,5.06,0.871,0.935,0.998,0.997,16.252
为了说明这个概念,这比需要的更冗长。这可以减少到:
perl -F, -lane 'print join ",", map { $_ eq "." ? "?" : $_ } @F'
如果您的 CSV 也有引号,那么您可以打开 Text::CSV
模块,它可以巧妙地处理这个问题。
只需要一次替换
$ perl -pe 's/,\.(?=,)/,?/g' dots.csv
1,987372,987372,C,T,?,?,?,?,?,?,?,?,1,D,?,?,?,?,?,?,?,1.293,12.23,0.989,0.973,D,?,?,?,?,0.253,0,4.08,0.917,1.048,1.000,1.000,12.998
1,987393,987393,C,T,?,?,?,?,?,?,?,?,1,D,?,?,?,?,?,?,0.152,1.980,16.09,0.999,0.982,D,-0.493,T,0.335,T,0.696,0,5.06,0.871,0.935,0.998,0.997,16.252
您只需要 2 遍,因为在 ,.,
匹配中找到的尾随 ,
无法匹配下一个 ,.,
中的前导 ,
:
$ sed 's/,\.,/,?,/g; s/,\.,/,?,/g' file
1,987372,987372,C,T,?,?,?,?,?,?,?,?,1,D,?,?,?,?,?,?,?,1.293,12.23,0.989,0.973,D,?,?,?,?,0.253,0,4.08,0.917,1.048,1.000,1.000,12.998
1,987393,987393,C,T,?,?,?,?,?,?,?,?,1,D,?,?,?,?,?,?,0.152,1.980,16.09,0.999,0.982,D,-0.493,T,0.335,T,0.696,0,5.06,0.871,0.935,0.998,0.997,16.252
以上将在任何 OS 上的任何 sed 中工作。