Perl - 在第 n 个定界符后替换
Perl - Substitute after nth delimiter
我需要一些帮助来替换我想在文件的行上执行的操作,如下所示:
aoipp;dadada.12312;ss;1245454;Xiop;12.12;45.3;47.897;31.5;
asdfafd;14355.54664;peasd;125.1;900.2;76.897;67.456;asdfdf;
perio;777.2;ipoes;900.34;2;1980.45;870.98;67.67;
我想用 ,
替换每个 .
,但只能在第五次出现分隔符 ;
之后。其他一切都需要保持不变。所以所需的输出文件将如下所示:
aoipp;dadada.12312;ss;1245454;Xiop;12,12;45,3;47,897;31,5;
asdfafd;14355.54664;peasd;125.1;900.2;76,897;67,456;asdfdf;
perio;777.2;ipoes;900.34;2;1980,45;870,98;67,67;
我主要对在 perl 中执行此操作很感兴趣,因此我可以将其合并到更大的程序中,但也欢迎使用 bash / awk 中的任何解决方案。提前致谢。
# this should do your work
sed -i 's/;/,/6g' filename
cat filename
aoipp;dadada.12312;ss;1245454;Xiop;12.12,45.3,47.897,31.5,
asdfafd;14355.54664;peasd;125.1;900.2;76.897,67.456,asdfdf,
perio;777.2;ipoes;900.34;2;1980.45,870.98,67.67,
这个 awk 单行代码应该适合你:
awk -F';' -v OFS=";" '{for(i=6;i<=NF;i++)gsub("[.]",",",$i)}7' file
它从第 6 个字段开始(;
分隔),每个字段将所有 .
替换为 ,
。
使用您的数据进行测试:
kent$ cat f
aoipp;dadada.12312;ss;1245454;Xiop;12.12;45.3;47.897;31.5;
asdfafd;14355.54664;peasd;125.1;900.2;76.897;67.456;asdfdf;
perio;777.2;ipoes;900.34;2;1980.45;870.98;67.67;
kent$ awk -F';' -v OFS=";" '{for(i=6;i<=NF;i++)gsub("[.]",",",$i)}7' f
aoipp;dadada.12312;ss;1245454;Xiop;12,12;45,3;47,897;31,5;
asdfafd;14355.54664;peasd;125.1;900.2;76,897;67,456;asdfdf;
perio;777.2;ipoes;900.34;2;1980,45;870,98;67,67;
我使用数组切片 @fields[ 5 .. $#fields ]
来仅访问要更改的元素。
#!/usr/bin/perl
use warnings;
use strict;
my @input = qw( aoipp;dadada.12312;ss;1245454;Xiop;12.12;45.3;47.897;31.5;
asdfafd;14355.54664;peasd;125.1;900.2;76.897;67.456;asdfdf;
perio;777.2;ipoes;900.34;2;1980.45;870.98;67.67;
);
my @expected = qw( aoipp;dadada.12312;ss;1245454;Xiop;12,12;45,3;47,897;31,5;
asdfafd;14355.54664;peasd;125.1;900.2;76,897;67,456;asdfdf;
perio;777.2;ipoes;900.34;2;1980,45;870,98;67,67;
);
sub process {
my (@input) = @_;
my @output;
for my $line (@input) {
my @fields = split /;/, $line;
s/\./,/ for @fields[ 5 .. $#fields ];
push @output, join ';', @fields, q();
}
return \@output
}
use Test::More tests => 1;
is_deeply(process(@input), \@expected);
while (my $line = <DATA>) {
if ($line =~ /^(?:[^;]*;){5}/) {
substr($line, $+[0]) =~ y/./,/;
}
print $line;
}
__DATA__
aoipp;dadada.12312;ss;1245454;Xiop;12.12;45.3;47.897;31.5;
asdfafd;14355.54664;peasd;125.1;900.2;76.897;67.456;asdfdf;
perio;777.2;ipoes;900.34;2;1980.45;870.98;67.67;
perl -pe 's/(.*?;){6}\K(.*)/ =~ s!\.!,!rg /ge'
- 跳过第 6 个之前的所有内容
;
((.*?;){6}\K
),
- 并应用替换。 , 到该行的其余部分 (
=~ s!\.!,!rg
)
我需要一些帮助来替换我想在文件的行上执行的操作,如下所示:
aoipp;dadada.12312;ss;1245454;Xiop;12.12;45.3;47.897;31.5;
asdfafd;14355.54664;peasd;125.1;900.2;76.897;67.456;asdfdf;
perio;777.2;ipoes;900.34;2;1980.45;870.98;67.67;
我想用 ,
替换每个 .
,但只能在第五次出现分隔符 ;
之后。其他一切都需要保持不变。所以所需的输出文件将如下所示:
aoipp;dadada.12312;ss;1245454;Xiop;12,12;45,3;47,897;31,5;
asdfafd;14355.54664;peasd;125.1;900.2;76,897;67,456;asdfdf;
perio;777.2;ipoes;900.34;2;1980,45;870,98;67,67;
我主要对在 perl 中执行此操作很感兴趣,因此我可以将其合并到更大的程序中,但也欢迎使用 bash / awk 中的任何解决方案。提前致谢。
# this should do your work
sed -i 's/;/,/6g' filename
cat filename
aoipp;dadada.12312;ss;1245454;Xiop;12.12,45.3,47.897,31.5,
asdfafd;14355.54664;peasd;125.1;900.2;76.897,67.456,asdfdf,
perio;777.2;ipoes;900.34;2;1980.45,870.98,67.67,
这个 awk 单行代码应该适合你:
awk -F';' -v OFS=";" '{for(i=6;i<=NF;i++)gsub("[.]",",",$i)}7' file
它从第 6 个字段开始(;
分隔),每个字段将所有 .
替换为 ,
。
使用您的数据进行测试:
kent$ cat f
aoipp;dadada.12312;ss;1245454;Xiop;12.12;45.3;47.897;31.5;
asdfafd;14355.54664;peasd;125.1;900.2;76.897;67.456;asdfdf;
perio;777.2;ipoes;900.34;2;1980.45;870.98;67.67;
kent$ awk -F';' -v OFS=";" '{for(i=6;i<=NF;i++)gsub("[.]",",",$i)}7' f
aoipp;dadada.12312;ss;1245454;Xiop;12,12;45,3;47,897;31,5;
asdfafd;14355.54664;peasd;125.1;900.2;76,897;67,456;asdfdf;
perio;777.2;ipoes;900.34;2;1980,45;870,98;67,67;
我使用数组切片 @fields[ 5 .. $#fields ]
来仅访问要更改的元素。
#!/usr/bin/perl
use warnings;
use strict;
my @input = qw( aoipp;dadada.12312;ss;1245454;Xiop;12.12;45.3;47.897;31.5;
asdfafd;14355.54664;peasd;125.1;900.2;76.897;67.456;asdfdf;
perio;777.2;ipoes;900.34;2;1980.45;870.98;67.67;
);
my @expected = qw( aoipp;dadada.12312;ss;1245454;Xiop;12,12;45,3;47,897;31,5;
asdfafd;14355.54664;peasd;125.1;900.2;76,897;67,456;asdfdf;
perio;777.2;ipoes;900.34;2;1980,45;870,98;67,67;
);
sub process {
my (@input) = @_;
my @output;
for my $line (@input) {
my @fields = split /;/, $line;
s/\./,/ for @fields[ 5 .. $#fields ];
push @output, join ';', @fields, q();
}
return \@output
}
use Test::More tests => 1;
is_deeply(process(@input), \@expected);
while (my $line = <DATA>) {
if ($line =~ /^(?:[^;]*;){5}/) {
substr($line, $+[0]) =~ y/./,/;
}
print $line;
}
__DATA__
aoipp;dadada.12312;ss;1245454;Xiop;12.12;45.3;47.897;31.5;
asdfafd;14355.54664;peasd;125.1;900.2;76.897;67.456;asdfdf;
perio;777.2;ipoes;900.34;2;1980.45;870.98;67.67;
perl -pe 's/(.*?;){6}\K(.*)/ =~ s!\.!,!rg /ge'
- 跳过第 6 个之前的所有内容
;
((.*?;){6}\K
), - 并应用替换。 , 到该行的其余部分 (
=~ s!\.!,!rg
)