变量未在perl中正确设置

时间:2014-09-28 15:07:27

标签: perl scope subroutine

我有以下代码:

#!/usr/bin/perl -w
use warnings;
use diagnostics;

open $fh, "<", "$ARGV[0]" or die "Could not open file: $!";

sub getsub {
    my $sub = $_[0];
    print "sub entered for $sub\n";
    while (<$fh>) {
        if ( /\.subckt $sub/ .. /\.ends/ ) {
            print;
        }
    }
}

while (<$fh>) {
    if ( $_ =~ /^xa1/ ) {
        $line = $_;
        print "line found to be $line\n";
        while ( ( my $nxt = readline($fh) ) =~ /^\+/ ) {
            $line = $nxt;
            print "line changed to $line\n";
        }
        $line =~ s/\s+$//;
        print "last line is $line\n";
        my $sub = ( split '\s', $line )[-1];
        print "subcircuit found is $sub in $line\n";
        getsub($sub);
    }
}

这里我试图在getsub例程中的两个模式之间打印一些文本。但是当我尝试运行它时,我进入子程序,但不进入子程序中的if块。我试图在以下文件上运行它:

.subckt a1 x y z
  xa a b c1
  xb c d e1
  xc f g h1
.ends

.subckt c1 x y z
  xa a b f
  xb c d e
  xc f g h
.ends

.subckt e1 x y z
  xa a b c1
  xb c d k1
  xc f g h1
.ends

xa1 a s f a1

我想在.subckt a1.ends之间打印文件内容。

我知道这可以通过命令行上的一个perl内核来完成,但我想为不同的文件创建一些通用脚本,所以我只需要这样做。上面的代码有什么问题。

3 个答案:

答案 0 :(得分:1)

我将使用不同的方法发布一个示例,而不是调整您的代码,IMO有点复杂。

#!/usr/bin/perl

use strict;
use warnings;

$/ = '';  # enable paragraph mode

while (<DATA>) {
    print if /^\.subckt a1/;
}

__DATA__

.subckt a1 x y z
  xa a b c1
  xb c d e1
  xc f g h1
.ends

.subckt c1 x y z
  xa a b f
  xb c d e
  xc f g h
.ends

.subckt e1 x y z
  xa a b c1
  xb c d k1
  xc f g h1
.ends

这是我先前解决方案的略微修改版本,它逐行循环遍历文件而不是段落模式。

#!/usr/bin/perl

use strict;
use warnings;

while (<DATA>) {
    if (/^\.subckt a1/ .. /^\.ends/) {
        print;
        print $/ if /^\.ends/
    }
}

__DATA__
.subckt a1 x y z
  xa a b f
  xb c d e
  xc f g h
.ends

.subckt a1 x y z
  xa a b c1
  xb c d e1
  xc f g h1
.ends

.subckt c1 x y z
  xa a b f
  xb c d e
  xc f g h
.ends

.subckt e1 x y z
  xa a b c1
  xb c d k1
  xc f g h1
.ends

我有第3种方法可以发布在你的perlmonks帖子上。

答案 1 :(得分:1)

  

上述代码有什么问题?

两件大事

  1. 始终在每个脚本中加入use strict;use warnings;

  2. 处理单个文件时,尽量不要使用两个while循环。

    如果您的文件在文件的不同部分需要特殊处理逻辑,则只需使用状态变量。

  3. 在这种情况下,要在两个标记之间打印文件的行,您只需要Range operator ..

    #!/usr/bin/perl -w
    use strict;
    use warnings;
    use diagnostics;
    use autodie;
    
    my $file = shift;
    
    #open my $fh, "<", $file;
    my $fh = \*DATA;
    
    while (<$fh>) {
        if ( my $range = /^\.subckt a1/ .. /^\.ends/ ) {
            print if $range != 1 && $range !~ /E/;
        }
    }
    
    __DATA__
    .subckt a1 x y z
      xa a b c1
      xb c d e1
      xc f g h1
    .ends
    
    .subckt c1 x y z
      xa a b f
      xb c d e
      xc f g h
    .ends
    
    .subckt e1 x y z
      xa a b c1
      xb c d k1
      xc f g h1
    .ends
    
    xa1 a s f a1
    

    输出:

      xa a b c1
      xb c d e1
      xc f g h1
    

    回答评论问题的附录

      

    我有三个问题:

         
        
    1. /E/函数的值$range代表什么?
    2.   

    阅读Range operator ..的perldoc:

      

    ...翻转翻转返回的值是false的空字符串,或者是true的序列号(以1开头)。为遇到的每个范围重置序列号。范围中的最终序列号具有字符串&#34; E0&#34;附加到它,它不会影响其数值,但如果要排除端点,则可以搜索。您可以通过等待序列号大于1来排除起始点。

    因此/ E /用于排除范围的结尾,因此我们不打印包含.ends的行。

      
        
    1. 您使用输入文件作为脚本的一部分,那么__DATA__做了什么?
    2.   

    我注释掉了输入文件句柄,而是使用了对*DATA的引用。

    #open my $fh, "<", $file;
    my $fh = \*DATA;
    

    *DATA是一个特殊的文件句柄,包含脚本中__DATA__之后的所有内容。这可以很方便地测试脚本并显示如何执行某些操作,而无需创建实际文件来加载测试。

      
        
    1. 另外,如果我有一个非常大的文件,我应该采用这种方法吗?
    2.   

    每当进行文件处理时,它们都应该逐行处理文件。这就是在这里完成的,因此这对大文件也适用。

答案 2 :(得分:0)

尝试下面的代码,如下所示:我刚在InputFile中添加了一个subckt a1,并提供了预期的输出。你在寻找这个或其他东西吗?

输入文件:

.subckt a1 x y z
       xa a b c1
       xb c d e1
       xc f g h1
     .ends

 .subckt c1 x y z
  xa a b f
  xb c d e
  xc f g h
.ends

.subckt e1 x y z
  xa a b c1
  xb c d k1
  xc f g h1
.ends

.subckt a1 p q r
        xa a b f
        xb c d e
        xc f g h
     .ends

xa1 a s f a1

您的代码已修改:

 use strict;
    use warnings;
    open my $fh , "<", "$ARGV[0]" or die "Could not open file: $!";
     sub getsub{
        my $sub = $_[0];
        print "sub entered for $sub\n";
        my $var = do {
             local $/ = undef;
             open my $fh1 , "<", "$ARGV[0]" or die "Could not open file: $!";
             <$fh1>;
            };

        while($var =~ /\.subckt\s*$sub(.*?)\.ends/isg) {
          print $1;
        }
    }

    while  (<$fh>) {
        #print $_;
      if ($_ =~ /^xa1/) {
        my $line = $_;
        print "line found to be $line\n";
        while ((my $nxt = (readline($fh)) =~ /^\+/)) {
          $line = $nxt;
          print "line changed to $line\n";
        }
        $line =~ s/\s+$//;
        print  "last line is $line\n";
        my $sub = (split '\s', $line)[-1];
        print "subcircuit found is $sub in $line\n"; 
        getsub($sub);
      }
    }

优化代码:

use strict;
use warnings;

my $document = do {
 local $/ = undef; 
 open my $fh , "<", "$ARGV[0]" or die "Could not open file: $!";
 <$fh>;
};

while($document =~ /\.subckt\s*a1(.*?)\.ends/isg)
 {
print $1;
  }

预期输出:

x y z
   xa a b c1
   xb c d e1
   xc f g h1

  p q r
    xa a b f
    xb c d e
    xc f g h