こんにちは、次のファイルがあります。
#0
0:()
1b:cg*b
1c
0:cg
xe
#4
0:()
0b:cg*b
xc
0:cg
1e
#8
0:()
0b:cg*b
xc
0:cg
xe
#12
1b:cg*b
xc
0:cg
0e
#16
xb:cg*b
1c
xe
#20
1:()
xb:cg*b
xc
1:cg
1e
#24
x:()
xb:cg*b
xc
xe
#28
0:()
1b:cg*b
0c
x:cg
0e
#29
0:()
0b:cg*b
1c
x:cg
xe
#32
0:()
1b:cg*b
これは#0
時間0を意味し、#8
時間8を意味する。今、あなたは与えられた時間範囲(例えば2〜30)に基づいてファイルの一部を印刷したいと思います(手動で入力したい)。
このファイルには時間2と30が存在しないため、出力は2以降の次の時間(#4)から30以降の次の時間(#32)前の行まで(結果的にtemp1 = line 7 to)でなければなりません。 50 OK)
temp1の出力は次のようになります。
#4
0:()
0bd*b
xc
0:cg
1e
#8
0:()
0bd*b
xc
0:cg
xe
#12
1bd*b
xc
0:cg
0e
#16
xbd*b
1c
xe
#20
1:()
xbd*b
xc
1:cg
1e
#24
x:()
xbd*b
xc
xe
#28
0:()
1bd*b
0c
x:cg
0e
#29
0:()
0bd*b
1c
x:cg
xe
ここで、()、bd * b、c、:cg、eは、2列目の最初の文字の後の文字列です。 0、1、x は最初の文字です。
temp2の出力は次のようになります。
4 8 12 16 20 24 28 29
:() 0 0 - - 1 x 0 0
b:cg*b 0 0 1 x x x 1 0
c x x x 1 x x 0 1
:cg 0 0 0 - 1 - x x
e 1 x 0 x 1 x 0 x
今計算する必要があります。 temp2の列1の各項目のxは、次の規則を出力します。
- 前に0または1が続くxのみを考慮してください。
- 前に他のxがある場合は、xを計算しないでください。
- 時間範囲の始めに発生した場合は、axを計算します。
- temp2 出力に 0,1,x 以外の文字がある場合は、この文字を無視する必要があります。
したがって、最終出力は次のようになります。
name count x
:() 1 x
b:cg*b 1 x
c 2 x
:cg 1 x
e 4 x
注:とにかく最終出力のみが必要なので、中間の一時出力ファイルをアーカイブする必要はありませんが、一時ファイルをアーカイブすることは私にとって有利です。明らかに、入力ファイルに空白行がある場合は、出力ファイルに空白行が必要ないので削除する必要があります)
私はスクリプトが最初で非常に長いtclスクリプトを書いたが、実行するのに時間がかかるので、awkまたはsedソリューションが欲しい。
ベストアンサー1
このPerlスクリプトは、必要な操作を一度に実行します。
#!/usr/bin/env perl
use strict;
use Getopt::Std;
## This hash will hold the options
my %opts;
## Read the options
getopts('t:s:e:',\%opts) || do { print "Invalid option\n"; exit(1); };
## Keep the temp file if the script is run
## with -t
my $keep_temp_file=$opts{t}||undef;
## The temp file's file handle
my $tmp;
## The temp file
my $temp_file=`mktemp`;
chomp($temp_file);
## Read the time range
my $start=$opts{s}||undef;
my $end=$opts{e}||undef;
## Open the input file
open($tmp,'<',"$ARGV[0]")||
die("Need an input file as the 1st argument: $!\n");
my ($time,$want);
my (%data,%letters);
## Read the input file
line:while (<$tmp>) {
## skip blank lines
next if /^\s*$/;
## remove trailing newlines
chomp;
## Is this line one of the start times?
if (/^#(\d+)/) {
if ($1>=$start && $1<=$end) {
$time=$1;
$want=1;
} elsif ($1>=$end) {
$want=0;
last line;
}
}
## If we want this line, save it in
## the %data hash.
if ($want==1) {
## Skip if this line is the one that has the time
## definition.
next if /^#/;
## Get the two characters of the line
/^(.)(.+)/;
$data{$time}{$2}=$1;
## Save each letter seen
$letters{$2}++;
}
}
## Once the file has been processed, create
## the temp file.
open($tmp,'>',$temp_file)||
die("Could not open temp file $temp_file for writing: $!\n");
my @times=sort {$a <=> $b } keys(%data);
print $tmp " ";
printf $tmp "%6s", "$_" for @times;
print $tmp "\n";
foreach my $letter (sort keys(%letters)) {
print $tmp "$letter " ;
foreach my $time (@times) {
defined $data{$time}{$letter} ?
printf $tmp "%6s","$data{$time}{$letter} " : printf $tmp "%6s","- ";
}
print $tmp "\n";
}
close($tmp);
## Process the tmp file to get your desired output
open(my $fh,'<',"$temp_file")||
die("Could not open temp file $temp_file for reading: $!\n");
## Print the header
printf "%-7s%6s%10s\n",'name', 'count', 'x';
while (<$fh>) {
## Skip first line
next if $.==1;
## Collect the columns
my @foo=split(/\s+/);
## get the letter
my $let=shift(@foo);
my $c=0;
## Check if the first one is an x
$c++ if $foo[0] eq 'x';
## Check the rest
for (my $i=1;$i<=$#foo;$i++) {
## Get the previous position. This is complicated
## since you want to ignore the non [01x] characters
my $prev="";
for (my $k=$i-1; $k>-1; $k--) {
if ($foo[$k]=~/^[01x]$/) {
$prev=$foo[$k];
last;
}
}
## If this is an x, increment c if
## the previous character was 0 or 1
if ($foo[$i] eq 'x' && ($prev=~/^[01]$/ || $prev=~/^$/)) {
$c++;
}
}
printf "%-7s%6s%10s\n", $let,$c,"x";
}
## If we want to keep the temp file, copy
## it to the file name given.
if ($keep_temp_file) {
system("cp $temp_file $keep_temp_file");
}
## else, delete it
else {
unlink($temp_file);
}
別の名前で保存すると、foo.pl
次のように実行できます。
foo.pl -s 2 -e 30 -t 2-30.temp file
-s
開始時間を設定し、-e
終了時間を設定してください。一時ファイルを保持するには、を指定します-t
。それ以外の場合、一時-t
ファイルは削除されます。
あなたの例では、次のものを生成します。
$ perl foo.pl -s 2 -e 30 -t aa file2
name count x
:() 1 x
:cg 1 x
b:cg*b 1 x
c 2 x
e 4 x
この質問に答える理由は興味深い質問であり、あなたがここに初めて来たからです。しかし、我々はスクリプトサービスではないことに注意してください。このような複雑な解決策が必要な質問は要点を超えています。私たちはあなたの特定の問題を解決することを喜んで助けますが、(通常)あなたのために完全なスクリプトを書くことはありません。
次に、何かを書き始め、直面した問題を切り離してください。一つ聞いてください特定各質問について質問をすると、このようにスクリプトを構成できます。