我有以下代码:
#!/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内核来完成,但我想为不同的文件创建一些通用脚本,所以我只需要这样做。上面的代码有什么问题。
答案 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)
上述代码有什么问题?
两件大事
始终在每个脚本中加入use strict;
和use warnings;
。
处理单个文件时,尽量不要使用两个while
循环。
如果您的文件在文件的不同部分需要特殊处理逻辑,则只需使用状态变量。
在这种情况下,要在两个标记之间打印文件的行,您只需要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
我有三个问题:
- 醇>
/E/
函数的值$range
代表什么?
阅读Range operator ..
的perldoc:
...翻转翻转返回的值是false的空字符串,或者是true的序列号(以1开头)。为遇到的每个范围重置序列号。范围中的最终序列号具有字符串&#34; E0&#34;附加到它,它不会影响其数值,但如果要排除端点,则可以搜索。您可以通过等待序列号大于1来排除起始点。
因此/ E /用于排除范围的结尾,因此我们不打印包含.ends
的行。
- 您使用输入文件作为脚本的一部分,那么
醇>__DATA__
做了什么?
我注释掉了输入文件句柄,而是使用了对*DATA
的引用。
#open my $fh, "<", $file;
my $fh = \*DATA;
*DATA
是一个特殊的文件句柄,包含脚本中__DATA__
之后的所有内容。这可以很方便地测试脚本并显示如何执行某些操作,而无需创建实际文件来加载测试。
- 另外,如果我有一个非常大的文件,我应该采用这种方法吗?
醇>
每当进行文件处理时,它们都应该逐行处理文件。这就是在这里完成的,因此这对大文件也适用。
答案 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