如果输入文件是:
400102-25,6:50,90005002,1
400102-25,6:50,90005004,2
400102-25,7:00,90002109,3
400102-25,7:00,90002107,4
400102-25,7:05,90002111,5
400102-25,7:05,90002106,6
6004-10,13:05,90006017,1
6004-10,13:05,90006022,2
6004-10,13:20,90006030,3
6004-10,13:20,90006015,4
6004-10,13:20,90006019,5
6004-10,13:30,90006034,6
6004-10,13:40,90006033,7
6004-10,13:40,90006002,8
有没有办法获得这个输出:
400102-25,6:50,90005002,1
400102-25,,90005004,2
400102-25,7:00,90002109,3
400102-25,,90002107,4
400102-25,,90002111,5
400102-25,7:05,90002106,6
6004-10,13:05,90006017,1
6004-10,,90006022,2
6004-10,13:20,90006030,3
6004-10,,90006015,4
6004-10,,90006019,5
6004-10,13:30,90006034,6
6004-10,,90006033,7
6004-10,13:40,90006002,8
我想删除字段2的重复项(逗号分隔)并用逗号替换,但保留每个序列的第一个和最后一个记录,由第4列确定。
我认为结果可以通过
部分获得 awk '{FS=OFS=","} { if(!seen[$1 $2]++) print $0 ; else print $1,","$3, $4 } END{print}' input
但这并不能解决所有问题。有什么建议吗?
答案 0 :(得分:2)
这个解决方案做了几个假设。对于从1到...的数字序列,第一个字段是相同的,即第一个字段对于每个序列是相同的宽度(字符数),并且第一个字段是按排序顺序。它不使用最后一个字段来确定记录组,而是通过第一个字段来确定。
#!/usr/bin/perl
use strict;
use warnings;
my %data;
while (<DATA>) {
my ($key, @tmp) = split /,/;
push @{ $data{$key} }, \@tmp;
}
for my $key (sort keys %data) {
my $aref = $data{$key};
my $end = $aref->[-1][0];
for my $rec (reverse @$aref[1 .. $#$aref - 1]) {
if ($rec->[0] eq $end) {
$rec->[0] = '';
}
else {
last;
}
}
my $beg = $aref->[0][0];
for my $rec (@$aref[1 .. $#$aref - 1]) {
if ($rec->[0] eq $beg) {
$rec->[0] = '';
}
else {
$beg = $rec->[0];
}
}
for my $line (@$aref) {
print join ",", $key, @$line;
}
}
__DATA__
400102-25,6:50,90005002,1
400102-25,6:50,90005004,2
400102-25,7:00,90002109,3
400102-25,7:00,90002107,4
400102-25,7:05,90002111,5
400102-25,7:05,90002106,6
600004-10,13:05,90006017,1
600004-10,13:05,90006022,2
600004-10,13:20,90006030,3
600004-10,13:20,90006015,4
600004-10,13:30,90006034,5
600004-10,13:40,90006033,6
600004-10,13:40,90006002,7
输出
400102-25,6:50,90005002,1
400102-25,,90005004,2
400102-25,7:00,90002109,3
400102-25,,90002107,4
400102-25,,90002111,5
400102-25,7:05,90002106,6
600004-10,13:05,90006017,1
600004-10,,90006022,2
600004-10,13:20,90006030,3
600004-10,,90006015,4
600004-10,13:30,90006034,5
600004-10,,90006033,6
600004-10,13:40,90006002,7
为了适应您的新数据要求,我取出了哈希并改为使用数组(以保留输入文件的原始顺序)。请注意,用于运行程序的命令将类似于:
perl test.pl dat3.txt
其中test.pl
是您的程序名称,dat3.txt
是要处理的输入文件。
#!/usr/bin/perl
use strict;
use warnings;
my @data = [split /,/, <>];
my $i = $data[0][3];
while (<>) {
my @temp = split /,/;
if ($temp[3] == ++$i) {
push @data, \@temp;
}
else {
process(@data);
@data = \@temp;
$i = $data[0][3];
}
}
process(@data);
sub process {
my @data = @_;
my $end = $data[-1][1];
for my $rec (reverse @data[1 .. $#data - 1]) {
if ($rec->[1] eq $end) {
$rec->[1] = '';
}
else {
last;
}
}
my $beg = $data[0][1];
for my $rec (@data[1 .. $#data - 1]) {
if ($rec->[1] eq $beg) {
$rec->[1] = '';
}
else {
$beg = $rec->[1];
}
}
print map join(",", @$_), @data;
}
输出是:
400102-25,6:50,90005002,1
400102-25,,90005004,2
400102-25,7:00,90002109,3
400102-25,,90002107,4
400102-25,,90002111,5
400102-25,7:05,90002106,6
6004-10,13:05,90006017,1
6004-10,,90006022,2
6004-10,13:20,90006030,3
6004-10,,90006015,4
6004-10,,90006019,5
6004-10,13:30,90006034,6
6004-10,,90006033,7
6004-10,13:40,90006002,8
答案 1 :(得分:1)
awk
救援
$ awk 'BEGIN{FS=OFS=","}
{if(a[$1]==$2) $2="";
else a[$1]=$2}1' file
400102-25,6:50,90005002,1
400102-25,,90005004,2
400102-25,7:00,90002109,3
400102-25,,90002107,4
400102-25,7:05,90002111,5
400102-25,,90002106,6
600004-10,13:05,90006017,1
600004-10,,90006022,2
600004-10,13:20,90006030,3
600004-10,,90006015,4
600004-10,13:30,90006034,5
600004-10,13:40,90006033,6
600004-10,,90006002,7
请注意,您的示例输出有时会删除重复项的第一个实例而不是第二个实例。这将保留第一个并删除重复项。
答案 2 :(得分:1)
<强>更新强>:
awk 'BEGIN{FS=OFS=","}
function w(k){
for(i in a){
s=split(a[i],t)
delete a[i]
}
for(i=1;i<=s;i+=4){
if((k || $1!=t[1])&& i+3!=s){
t[i+1]=""
}else{
t[i+5]=""
}
print t[i],t[i+1],t[i+2],t[i+3]
}
}
{if($1$2 in a){a[$1$2]=a[$1$2]","$0}else{w();a[$1$2]=$0}}
END{w(1)}' file
400102-25,6:50,90005002,1
400102-25,,90005004,2
400102-25,7:00,90002109,3
400102-25,,90002107,4
400102-25,,90002111,5
400102-25,7:05,90002106,6
6004-10,13:05,90006017,1
6004-10,,90006022,2
6004-10,13:20,90006030,3
6004-10,,90006015,4
6004-10,,90006019,5
6004-10,13:30,90006034,6
6004-10,,90006033,7
6004-10,13:40,90006002,8
答案 3 :(得分:0)
对于lua-shell,请这样写:
wws$ `cat demo/7.lua
vim:open("demo/7.txt")
lnum_of_b=new() --line count of block
lineid = 0
function collect()
last_id = -1
bid = 0 --block id
for i = 0, vim.lmax do
vim:Gn(i)
:$
if(vim:atoi() -1 ~= last_id)
bid = bid + 1
lnum_of_b[bid] = 0;
lnum_of_b[bid] = lnum_of_b[bid] + 1
last_id = vim:atoi()
end
end
function do_block(lnum)
prev_time = ""
for i = 1, lnum do
vim:Gn( lineid )
:f,wvf,y:
if( vim:clipboard() == prev_time)
if i == lnum then vim:k() end
:^f,wvf,hx:
else prev_time = vim:clipboard();
lineid = lineid + 1
end
end
collect()
for i = 1, #blocks do do_block( lnum_of_b[i] ) end
vim:print()
这是我机器上的演示:
wws$ source demo/7.lua
400102-25,6:50,90005002,1
400102-25,,90005004,2
400102-25,7:00,90002109,3
400102-25,,90002107,4
400102-25,,90002111,5
400102-25,7:05,90002106,6
600004-10,13:05,90006017,1
600004-10,,90006022,2
600004-10,13:20,90006030,3
600004-10,,90006015,4
600004-10,13:30,90006034,5
600004-10,,90006033,6
600004-10,13:40,90006002,7
我认为我没有弄错你的意思:你想要一个块的最后一行保持并转向删除超出它的重复行。是? 上面的脚本不是最好的,因为luashell远非完整,但它可以实现尴尬措施的目标。 这只是他的理念:你总能实现目标。
答案 4 :(得分:0)
一些导入点
awk '{FS=OFS=","} { if(!seen[$1 $2]++)
..
将FS=OFS=","
替换为BEGIN{FS=OFS=","}
,或者可以在awk语句之外进行声明
从您的数组++
中删除seen[$1 $2]++
..此++
为变量提供计数器值
下面的短一个衬垫也许可以起作用
awk -v FS=',' -v OFS=',' '{if(($1 in a) && (a[$1]==$2)){$2="";print}else{print;a[$1]=$2;}}'
输出
400102-25,6:50,90005002,1
400102-25,,90005004,2
400102-25,7:00,90002109,3
400102-25,,90002107,4
400102-25,7:05,90002111,5
400102-25,,90002106,6
600004-10,13:05,90006017,1
600004-10,,90006022,2
600004-10,13:20,90006030,3
600004-10,,90006015,4
600004-10,13:30,90006034,5
600004-10,13:40,90006033,6
600004-10,,90006002,7