我有一个测试文件,看起来是这样的:
t # 3-0, 1
v 0 0
v 1 19
v 2 2
u 0 1 2
u 0 2 2
u 1 2 2
t # 3-1, 1
v 0 0
v 1 15
v 2 2
u 0 1 2
u 0 2 2
u 1 2 2
t # 3-2, 1
v 0 0
v 1 17
v 2 2
u 0 1 2
u 0 2 2
u 1 2 2
t # 3-3, 1
v 0 0
v 1 18
v 2 7
u 0 1 2
u 0 2 2
u 1 2 2
我编写了以下代码来匹配事务的最后三行(每个事务以t #
开头)
#!/usr/bin/perl -w
use strict;
my $input = shift @ARGV or die $!;
open (FILE, "$input") or die $!;
LOOP: while (<FILE>) {
if (m/^(t\h*#\h*[0-9,\h-]+)/) {
my $transaction_id = $1;
while (<FILE>) {
if (m/^(u\h+[0]\h+[1]\h+[2])/) {
my $edge_1 = $1;
while (<FILE>) {
if (m/^(u\h+[0]\h+[2]\h+[2])/) {
my $edge_2 = $1;
while (<FILE>) {
if (m/^(u\h+[1]\h+[2]\h+[2])/) {
my $edge_3 = $1;
print $transaction_id . "\t" . $edge_1 . "\t" . $edge_2 . "\t" . $edge_3 . "\n";
next LOOP;
}
}
}
}
}
}
}
}
close FILE;
但是,它没有打印任何结果。当我编译我的程序时,它运行时没有错误。我的最终目标是产生这样的输出,其中输出子图"u 0 1 2“、"u 0 2 2”和"u 12 2“的边:
t # 3-0, 1 u 0 1 2 u 0 2 2 u 1 2 2
t # 3-1, 1 u 0 1 2 u 0 2 2 u 1 2 2
t # 3-2, 1 u 0 1 2 u 0 2 2 u 1 2 2
t # 3-3, 1 u 0 1 2 u 0 2 2 u 1 2 2
发布于 2020-08-17 02:28:38
一种方法:将事务的所有行保留在缓冲区中,当您到达一个新的事务id存储前一行,以及该缓冲区中的最后三行时。
use warnings;
use strict;
use feature 'say';
my (@transactions, @trans_lines, $tid);
while (<>) {
chomp;
if (/^(t\s*#\s*[0-9,\s-]+)/) {
if (not $tid) {
$tid = $1; # the very first one starts
next;
}
# Store previous id and its last three lines, reset
push @transactions, [ $tid, @trans_lines[-3..-1] ];
$tid = $1;
@trans_lines = ()
}
push @trans_lines, $_;
}
say "@$_" for @transactions;
这会将所有事务存储在一个数组中,因此它们可以很容易地迭代并维护文件中的顺序。这支持使用问题中显示的结果。但是,对于数组,很难引用特定的数组,如果能够查找特定id,可以考虑使用数组引用的散列,比如在related problem中。
上面的代码依赖于事务中始终有三行,这在问题中是隐含的。我建议增加一张支票。
构造while (<>)
读取命令行或STDIN
上给定的所有文件行。
对已发布代码的一些评论
use warnings;
比使用use warnings;
更好$!
variable保存错误字符串。虽然它确实应该广泛使用,但是如果@ARGV
是空的,则shift
返回一个undef
,并且没有错误;因此没有设置$!
。相反,做一些类似的事情我的$file = shift @ARGV // die“用法:$0 file\n";
或者,更好的是,使用更完整的使用消息来调用例程,等等,。
(FH
)
open my $fh, '<', $file or die $!;
),因为它们在多方面明显优于globs
。
从相同资源(此处的文件句柄)读取的
我不太明白为什么问题中的代码不起作用。添加打印语句?
发布于 2020-08-17 10:36:45
您的代码为我提供了以下输出:
t # 3-0, 1 u 0 1 2 u 0 2 2 u 1 2 2
t # 3-1, 1 u 0 1 2 u 0 2 2 u 1 2 2
t # 3-2, 1 u 0 1 2 u 0 2 2 u 1 2 2
t # 3-3, 1 u 0 1 2 u 0 2 2 u 1 2 2
看来问题就出在你没给我们看的东西上。也许输入文件来自不同的系统,并且有您的系统无法识别的行尾。
嵌套的while
循环和if
条件使代码变得比需要的更复杂(因此更难维护)。您可以在一个循环中使用以下内容完成所有操作:
#!/usr/bin/perl
use strict;
use warnings;
my $input = shift @ARGV or die $!;
open (my $fh, '<', $input) or die $!;
my ($transaction_id, $edge_1, $edge_2, $edge_3);
while (<$fh>) {
if (m/^(t\h*#\h*[0-9,\h-]+)/) {
$transaction_id = $1;
} elsif (m/^(u\h+[0]\h+[1]\h+[2])/) {
$edge_1 = $1;
} elsif (m/^(u\h+[0]\h+[2]\h+[2])/) {
$edge_2 = $1;
} elsif (m/^(u\h+[1]\h+[2]\h+[2])/) {
$edge_3 = $1;
}
if ($transaction_id and $edge_1 and $edge_2 and $edge_3) {
print "$transaction_id\t$edge_1\t$edge_2\t$edge_3\n";
($transaction_id, $edge_1, $edge_2, $edge_3) = (undef) x 4;
}
}
(注意,我还将-w
替换为use warnings
,转而使用词法文件句柄和open()
的三arg版本。所有这些都是现代Perl最佳实践。)
发布于 2020-08-17 01:20:47
请您试一试:
#!/usr/bin/perl -w
my $ref;
open(FH, shift) or die;
while (<FH>) {
chop;
if (/^t\s*#/) { # if a new transaction starts
$ref = []; # then create a new reference to an array
push(@refs, $ref); # and memorize the reference
}
push(@$ref, $_); # append the line to the current array
}
for $ref (@refs) {
print(join(" " x 4, $ref->[0], $ref->[-3], $ref->[-2], $ref->[-1]), "\n");
}
输出:
t # 3-0, 1 u 0 1 2 u 0 2 2 u 1 2 2
t # 3-1, 1 u 0 1 2 u 0 2 2 u 1 2 2
t # 3-2, 1 u 0 1 2 u 0 2 2 u 1 2 2
t # 3-3, 1 u 0 1 2 u 0 2 2 u 1 2 2
https://stackoverflow.com/questions/63442271
复制相似问题