Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/perl/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Bash 仅从csv文件中删除*部分*句号_Bash_Perl_Sed_Tr - Fatal编程技术网

Bash 仅从csv文件中删除*部分*句号

Bash 仅从csv文件中删除*部分*句号,bash,perl,sed,tr,Bash,Perl,Sed,Tr,如果我有以下几行: 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

如果我有以下几行:

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
这似乎只在某些情况下起作用。i、 e.仍然有,、的例子

有人有什么建议吗

谢谢

这应该可以:

sed ':a;s/,\.,/,?,/g;ta' file
对于连续的、、字符串,替换成功后,下一个要处理的字符如下。这与模式不匹配,所以你需要第二次传球

:a是即将到来的循环的标签

,\,将匹配逗号之间的点。请注意,点必须转义,因为。用于匹配任何字符,a,将匹配

g表示一般替换

$ 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
ta测试先前的替换,如果成功,则循环到:剩余替换的标签。

这应该可以:

sed ':a;s/,\.,/,?,/g;ta' file
对于连续的、、字符串,替换成功后,下一个要处理的字符如下。这与模式不匹配,所以你需要第二次传球

:a是即将到来的循环的标签

,\,将匹配逗号之间的点。请注意,点必须转义,因为。用于匹配任何字符,a,将匹配

g表示一般替换

$ 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

ta测试以前的替换,如果成功,则循环到:剩余替换的标签。

使用sed,可以通过运行如上面答案所示的循环来实现,但是使用带lookarounds的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

此命令不需要循环,因为我们不需要匹配周围的逗号,而只是使用lookback和lookahead来声明它们的位置。

使用sed,可以通过运行如上面答案所示的循环来实现,但是使用带lookarounds的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
此命令不需要循环,因为我们只需使用lookback和lookahead来声明它们的位置,而不需要匹配周围的逗号。

您有一个使用sed样式正则表达式的示例。我将提供另一种选择—解析CSV,然后将每件事都视为一个“字段”:

#!/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
如果您的CSV也有引用,那么您可以打开Text::CSV模块,该模块可以灵活地处理该问题

您有一个使用sed样式正则表达式的示例。我将提供另一种选择—解析CSV,然后将每件事都视为一个“字段”:

#!/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

如果您的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

所需要的只是一次替换

$ 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次传球,因为在a上找到的尾随,在下一个,,,上的匹配无法与前导匹配:


上述方法适用于任何操作系统上的任何sed。

您只需通过两次,因为在一个,,,匹配上找到的尾随无法匹配下一个,,,上的前导:


以上内容适用于任何操作系统上的任何sed。

谢谢Kenavoz。这已经奏效了。我怀疑是这样的。如果你不介意的话,你能解释一下每个部分是如何工作的吗?我只懂s/,\,/,?,/g。还有,为什么要在考试之前逃学呢?在需要一个合适的正则表达式模式才能在一次考试中运行的情况下,进行两次考试有点笨重go@Borodin你会推荐哪个sed正则表达式?@Kenavoz:我不会推荐sed正则表达式regex@Borodin您似乎没有合适的正则表达式来建议使用另一种使用perl的方法。只要回答你的评论就行了。谢谢Kenavoz。这已经奏效了。我怀疑是这样的。如果你不介意的话,你能解释一下每个部分是如何工作的吗?我只懂s/,\,/,?,/g。还有,为什么要在考试之前逃学呢?在需要一个合适的正则表达式模式才能在一次考试中运行的情况下,进行两次考试有点笨重go@Borodin你会推荐哪个sed正则表达式?@Kenavoz:我不会推荐sed正则表达式regex@Borodin您似乎没有合适的正则表达式来建议使用另一种使用perl的方法。只要回答你的评论就行了。