我有许多包含分层相关字符串的文本文件。
修改以下是一个示例。这些文件基本上如下所示
HEBV000000000000
HEH11111111 2222222022HCPP 3333 0000 AAA
HET11111 22222222222222
HEH888888 3333333333HCPP 3333 0000 AAA
HET2222 33333333333333333
HEH44444444 55555555HCPP 4444 0000 BBB
HET555555 0066666666666666666
HEE0019000000090
HEBV0120150301429
HEH5588558888 5555000044440000NCPP 164201503010000 HIP
HER9999A 0157000120150303333
HET8888B 0036400120150303333
HEE0044000000040
细分是:
HEB (start of batch1)
HEH (start of group1)
HET (end of group1)
HEH (start of group2)
HET (end of group2)
HEH (start of group3)
HET (end of group3)
HEE (end of batch1)
HEB (start of batch 2)
HEH (start of group1)
HER (start of subgroup1)
HET (end of group1)
HEE (end of batch2)
字符串在几个方面相关:
HEB字符串表示批处理的开头。 HEE详细说明了前一批中的HEH,HER和HET记录的数量。
下一个关系是文档的内容,即HER和HET记录与单个HEH相关。批次(HEB到HEE)可以包含多个HEH-HER-HET组。一批中总会至少有一个HEH-HET组;可能有很多。如果存在HER记录,则其与其前面的HEH和其后的所有HET相关,直到遇到新的HER或HEH。因此,HER和HET记录仅与单个HEH记录相关,但HEH记录可与多个HER和HET记录相关联。
任何字符串中都没有链接标识符。那么唯一可用的关系是文件中字符串的位置。 (不是我的行为,我无法改变这一点)
我想要做的是有一个基于HET记录的输出文件,如下所示,以便我可以导入统计包(请注意,我的意思是从每行打印整个字符串,但是易于阅读我只是显示字符串的HE *:
HET1 HEH1 HEB FILENAME HEE
HET2 HEH2 HER2 HEB FILENAME HEE
HET3 HEH3 HER3 HEB FILENAME HEE
等等。
我认为它的工作原理是:
Read in the file
Get filename and append to HEB records
Then
Look for HEB record and store
Look for HEE record and store
Append HEB and HEE to HEH
if new HEB is found repeat above until end of file
Then
Look for HEH record and store
Append to HET records until an HEH or HEE record is found
if a new HEH is found, append it to HET records until HEH or HEE is found
repeat until eof
Then
Look for HER record and store
Append to HET records until an HER, HEH or HEE record is found
if a new HER is found, append it to HET records until an HER, HEH or HEE record is found
repeat until eof
save to new file
我认为这会让我进入
HET1 HEH1 HEB FILENAME HEE
HET2 HEH2 HER2 HEB FILENAME HEE
HET3 HEH3 HER3 HEB FILENAME HEE
我以前用类似格式的文件提出了类似的问题:
和
bash & awk: Loop through dir running two separate awk commands on all files and saving in new dir
不幸的是,由于多层关系,这些文件更复杂。这超出了我从其他问题修改解决方案的能力
代码:
for f in *txt
do
awk '/^AB1/{ab1=$0;next}/^AB2/{print $1, $2, ab1}' "$f" > "new$f"
awk '{print $1,$2,$3,$4,$5,$6,FILENAME}' "new$f" > "newnew$f"
done
我不知道awk在这里是不是一个好主意,或者像Perl或Java这样的东西会更好。正如我在其他问题中所提到的,我是医生,而不是程序员,虽然我可以通过一些理解来修改代码(通常绊倒我的脚),当我遇到这样的事情时,我发现自己远离我的深度。
答案 0 :(得分:1)
我认为这可以按照您的意愿进行,但您的描述有点不透明
该程序会跟踪最近的HEB和HEH记录的值,以及自上次HEH或HET以来的所有HER记录
我使用了输入文件中每一行的第一个字段。目前还不清楚这是否足够,或者您是否需要整行中的数据
输出记录的内容在遇到HET时保存在数组@records
中,但此时它们缺少HEE信息,因此无法打印
在每个HEE记录中,所有等待的输出与当前记录的值一起打印,并且等待列表被清空
请注意,我已经从您自己的示例略微更改了输入,以允许每个HEH有多个HET记录,每个HET有多个HER记录
第@ARGV = 'f1.txt'
行模拟命令行上的参数,就像您输入了perl process_data.pl f1.txt
一样。您应该在使用代码之前删除此行,并且目标方法是使用glob模式作为参数,以便shell找到所有相关文件并将它们传递给代码
use strict;
use warnings 'all';
use feature 'state';
@ARGV = 'f1.txt';
my ( $heb, $heh, @her );
my @records;
while ( <> ) {
my ($item) = split;
die unless my ($type) = $item =~ /^(HE[BHRTE])/;
state $dispatch = {
HEB => sub {
$heb = shift;
$heh = undef;
@her = ();
},
HEH => sub {
$heh = shift;
@her = ();
},
HER => sub {
push @her, shift;
},
HET => sub {
my $het = shift;
my $filename = $ARGV;
push @records, [ $het, $heh, @her, $heb, $filename ];
@her = ();
},
HEE => sub {
my $hee = shift;
for my $rec (@records) {
push @$rec, $hee;
print "@$rec\n";
}
$heb = $heh = undef;
@her = ();
@records = ();
},
};
$dispatch->{$type}->($item);
}
HEBV000000000000
HEH11111111 2222222022HCPP 3333 0000 AAA
HET11111 22222222222222
HEH888888 3333333333HCPP 3333 0000 AAA
HET2222 33333333333333333
HEH44444444 55555555HCPP 4444 0000 BBB
HET555555 0066666666666666666
HEE0019000000090
HEBV0120150301429
HEH5588558888 5555000044440000NCPP 164201503010000 HIP
HER9999A 0157000120150303333
HER9999B 0157000120150303333
HET8888B 0036400120150303333
HER9999C 0157000120150303333
HER9999D 0157000120150303333
HET8888B 0036400120150303333
HEE0044000000040
HET11111 HEH11111111 HEBV000000000000 f1.txt HEE0019000000090
HET2222 HEH888888 HEBV000000000000 f1.txt HEE0019000000090
HET555555 HEH44444444 HEBV000000000000 f1.txt HEE0019000000090
HET8888B HEH5588558888 HER9999A HER9999B HEBV0120150301429 f1.txt HEE0044000000040
HET8888B HEH5588558888 HER9999C HER9999D HEBV0120150301429 f1.txt HEE0044000000040
答案 1 :(得分:0)
我担心你的文件实际上的样子并不完全清楚 - 但如果不专注于逐行,你可以更轻松地做到这一点线处理。
特别有两个技巧 - 第一个使用$/
设置记录分隔符并以块的形式读取文件。
所以例如:
#!/usr/bin/perl
use strict;
use warnings;
local $/ = 'HEE';
while ( <DATA> ) {
print "\nStart of Record\n";
print;
print "\nEnd of Record\n";
}
__DATA__
HEB (start of batch1)
HEH (start of group1)
HET
HET
HET (end of group1)
HEH (start of group2)
HET
HET (end of group2)
HEE (end of batch1)
每次点击文件中的“HEB”标记时,都会循环显示循环。此时,您可以应用正则表达式匹配来提取子元素。所以看着它 - HEH分离了子记录:
my @groups = m/^(HEH .*?(?=HE[HE]))/gms;
foreach my $group ( @groups ) {
print "Start of group:\n";
print $group;
print "End of group\n";
}
这使用正则表达式和零宽度模式来捕获'HEH'和'HEH'或'HEE'之间的文本块,给出:
Start of group:
HEH (start of group1)
HET
HET
HET (end of group1)
End of group
Start of group:
HEH (start of group2)
HET
HET (end of group2)
End of group
结合这两种技巧,你应该能够在你的记录中选择你想要的东西。我担心我不能给你一个更详细的例子,因为我真的需要一个更完整的输入和输出示例。
#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
local $/ = 'HEE';
while ( <DATA> ) {
print "\nStart of Record\n";
print;
print "\nEnd of Record\n";
my @groups = m/^(HEH .*?(?=HE[HE]))/gms;
foreach my $group ( @groups ) {
print "Start of group:\n";
print $group;
print "End of group\n";
my @HET = $group =~ m/HET (.*)$/gm;
print "HET lines: \n";
print join "\n", @HET,"\n";
}
}
__DATA__
HEB (start of batch1)
HEH (start of group1)
HET
HET
HET (end of group1)
HEH (start of group2)
HET
HET (end of group2)
HEE (end of batch1)
HEB (start of batch 2)
HEH (start of group1)
HER (start of subgroup1)
HET
HET
HER (start of subgroup2)
HET
HEH (start of group2)
HET (end of group2)
HEE (end of batch 2)
答案 2 :(得分:0)
承认不理解这种格式和目的(以及提出这种格式的人的心态)并假设它具有一致的结构,这可能有效
$ awk '/HER/{r++;m=0}
!m&&/HET/{m++; t++;
print $1 t, "HEH" t, (r?"HER"t OFS:"") "HEB", FILENAME, "HEE";next}' heb
HET1 HEH1 HEB heb HEE
HET2 HEH2 HER2 HEB heb HEE
HET3 HEH3 HER3 HEB heb HEE
答案 3 :(得分:0)
如果您想使用awk执行此操作:
gawk -v RS="HEB" '{
for(i=2;i<NF;i++){
if( $i ~ /^HE[R|H]/){
x=x" "$i
};
if( $i ~ /^HET/ ){
print $i""x,"HEB"$1,FILENAME,$NF;x=""
}
}
}' file.txt