首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >regex匹配不产生perl中的输出。

regex匹配不产生perl中的输出。
EN

Stack Overflow用户
提问于 2020-08-16 21:51:54
回答 4查看 107关注 0票数 2

我有一个测试文件,看起来是这样的:

代码语言:javascript
运行
复制
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 #开头)

代码语言:javascript
运行
复制
#!/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“的边:

代码语言:javascript
运行
复制
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
EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2020-08-17 02:28:38

一种方法:将事务的所有行保留在缓冲区中,当您到达一个新的事务id存储前一行,以及该缓冲区中的最后三行时。

代码语言:javascript
运行
复制
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上给定的所有文件行。

对已发布代码的一些评论

-w switch

  • use warnings;比使用use warnings;更好

  • $! variable保存错误字符串。虽然它确实应该广泛使用,但是如果@ARGV是空的,则shift返回一个undef,并且没有错误;因此没有设置$!。相反,做一些类似的事情

我的$file = shift @ARGV // die“用法:$0 file\n";

或者,更好的是,使用更完整的使用消息来调用例程,等等,。

(FH)

  • 使用词法文件句柄( open my $fh, '<', $file or die $!; ),因为它们在多方面明显优于globs

  • 没有必要重复引用一个单独的标量变量,因为它无论如何都会得到评估(而过度引用甚至会在某些情况下导致微妙的问题)

从相同资源(此处的文件句柄)读取的

  • 嵌套循环是合法的,有其用途,但它增加了一层复杂性,使代码难以跟踪。我会非常非常谨慎地使用它。多层嵌套增加了更多的复杂性。

我不太明白为什么问题中的代码不起作用。添加打印语句?

票数 4
EN

Stack Overflow用户

发布于 2020-08-17 10:36:45

您的代码为我提供了以下输出:

代码语言:javascript
运行
复制
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条件使代码变得比需要的更复杂(因此更难维护)。您可以在一个循环中使用以下内容完成所有操作:

代码语言:javascript
运行
复制
#!/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最佳实践。)

票数 3
EN

Stack Overflow用户

发布于 2020-08-17 01:20:47

请您试一试:

代码语言:javascript
运行
复制
#!/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");
}

输出:

代码语言:javascript
运行
复制
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
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/63442271

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档