我收到错误“在./test.pl第20行的子程序条目中使用未初始化的值”。当我运行以下代码时。
2015-05-01 abc serv1 X View impl details 34 33 2 0 1 0 4552 3312 0 72 0 0 0 0 0 0 0
0 1 576 3 1 0 0 0 0 0 0 0 0 0.0 0 0 0 0 0 0 0 0 0 0 0 0
0 1 381 671 1
2015-05-01 def serv2 X Assessment for next exam preview 22 22 0 0 1 0 1195 3577 0 3053 0 0 0 2 2 0
0 0 26 163 10 2 0 0 0 0 0 0 0 0 0.0 0 0 0 0 0 0 0 0 0 0 0
0 0 12 5 21 1
由空格分隔的前4个字段必须按原样打印。但是,正如您所看到的,病房的第5个字段,可以有任意数量的空格分隔字。我想把它们作为第5场聚集在一起,直到找到一个数字作为下一个场。在上面的示例输入中,我希望“查看impl详细信息”为第5个字段而不是“视图”为第5个,“impl”为第6个,详细信息为第7个字段。第二行数据也是如此。我希望“下次考试预览评估”显示为第5场&其余的都是他们自己的领域。
#!/usr/bin/perl
use strict;
use warnings;
use POSIX;
my $i_file='../out/test.out';
my $o_file='../sql/test.out';
my $text_cont="";
open (FILE, $i_file) or die "Could not read from $i_file, program halting.";
while(<FILE>) {
(my $fl_1, my $fl_2, my $fl_3, my $fl_4, my @subfields) = split;
my @join_fields;
my $l=0;
for (my $k=5; $k <= 53; $k++) {
$join_fields[$l] = "";
if(isdigit($subfields[$k])) {
$join_fields[$l] = $subfields[$k];
$l = $l + 1;
}
else {
$join_fields[$l] = $join_fields[$l] . $subfields[$k];
}
}
}
close FILE;
我想从文件中读取数千行,每行包含50个以空格分隔的字段。我正在读取每一行,按空格分割数据作为分隔符开始。从病房的第5个区域开始,直到我得到一个带有数字的字段,我想将字段附加到第5个字段。然后最后打印出输出。
我是Perl的新手。我对错误的理解是它无法找到“isdigit”的定义。但是,考虑到互联网上的一些解决方案,我使用了POSIX包。它似乎没有帮助。有人可以帮助我达到我的要求吗?
#!/usr/bin/perl
use strict;
use warnings;
my $i_file='../out/test.out';
my $o_file='../sql/test.sql';
my $text_cont=" ";
open (FILE, $i_file) or die "Could not read from $i_file, program halting.";
while(<FILE>) {
(my $fl_1, my $fl_2, my $fl_3, my $fl_4, my @subfields) = split;
my @join_fields;
my $l=0;
foreach my $k_val ( @subfields ) {
#$join_fields[$l] = "";
if ($k_val ne " ") {
if ( $k_val =~ m/^\d+$/ ) {
$join_fields[$l] = $k_val;
$l = $l ++;
}
else {
my $temp = $join_fields[$l];
my $new_val = $temp.$k_val;
$join_fields[$l] = $new_val;
}
$text_cont = $text_cont."$join_fields[0]";
}
}
}
close FILE;
open STDOUT, ">", $o_file or die "$0: open: $!";
print "$text_cont";
close STDOUT;
答案 0 :(得分:3)
如果这些确实是固定宽度的字段,在复制期间会被破坏。粘贴,你应该使用unpack
。否则,您可以利用specify a limit when using split
:
如果指定了
LIMIT
且为正,则表示EXPR
可能被分割的最大字段数;换句话说,LIMIT
比EXPR
可能被分割的最大次数大一个。
问题的原始措辞似乎暗示第五个字段,下面称为$msg
,从不包含数字。根据OP的评论显示至少有一行,其中字段包含文本WD25
,我正在更新下面的模式,以便更容许该字段中的文本。
#!/usr/bin/env perl
use strict;
use warnings;
my $i_file = 'userpf.input';
open my $IN, '<', $i_file
or die "Cannot open '$i_file': $!";
my @data;
while (my $line = <$IN>) {
next unless $line =~ /\S/;
my ($date, $type, $serv, $flag, $rest) = split ' ', $line, 5;
my ($msg, $fields) = ($rest =~ /^ (.+?) \s+ ([0-9] .+) /x);
push @data, [ $date, $type, $serv, $flag, $msg, split(' ', $fields) ];
}
for my $x (@data) {
print "'$_'\n" for @$x;
}
我冒昧地给最初的字段命名。
答案 1 :(得分:1)
如果没有您的源信息,我无法确定,但您认为这里可能有一个围栏帖错误:
(my $fl_1, my $fl_2, my $fl_3, my $fl_4, my @subfields) = split;
for (my $k=5; $k <= 53; $k++) {
if(isdigit($subfields[$k])) {
你将@subfields从5迭代到53.但是第一个'subfield'字段是列表中的'4th'字段。除非你真的是从字段9-57
开始。
我不认为你这样做,因为即使你在样品线上取出“包装” - 你的“子字段”也只有51个元素。这是您的问题的根源。
您还应该注意,split
在任何空格上都会分裂。
因此,您获得@subfields
包含:
$VAR1 = [
'View',
'impl',
'details',
'34',
'33',
'2',
但是我建议你可能不想这样做 - 你只使用$k
索引@subfields
。
那么为什么不呢:
foreach my $k_val ( @subfields ) {
if ( isdigit $k_val ) {
# etc...
}
}
但你也是对的 - 我收到警告isdigit
已被弃用:
不推荐使用的函数,其使用会引发警告,并且将在未来的Perl版本中删除。它非常类似于匹配qr / ^ [[:digit:]] + $ / x,你应该转换为使用它。
有多种方法可以做类似的事情 - 我建议您可能需要:
if ( $k_val =~ m/^\d+$/ ) {
将使用正则表达式检查$k_val
是否仅为数字(1个或更多数字字符)。
答案 2 :(得分:1)
根据我的理解你的要求,我修改了你的脚本。我已将输入记录分隔符$/
从\n
修改为2015
,因为您要处理的所需字符串由换行符分隔,虽然解决方案非常简单,但它可以正常工作:
我建议您检查File::Stream以使输入记录分隔符$/
成为正则表达式,即值不是2015
或其他内容。
#!/usr/bin/perl
use strict;
use warnings;
local $/="2015"; # set input record separator as 2015
open my $fh, '<','file' or die "unable to open file: $! \n";
my @subfields;
my $junk=<$fh>; # remove first one
while(<$fh>){
chomp; # remove 2015 from last
$_= $junk.$_; # concatenate 2015 at begining of $_
(my $fl_1, my $fl_2, my $fl_3, my $fl_4, my @subfields) = split;
my @join_fields;
my $new_val="";
foreach my $k_val ( @subfields ) {
if ( $k_val =~ m/^\d+(.\d+)?$/ ) {
push(@join_fields,$k_val);
}
else{
$new_val .= $k_val;
}
}
push(@join_fields,$new_val);
my $fl_5 = pop @join_fields; # pop out your fifth field here
print "$fl_1 $fl_2 $fl_3 $fl_4 $fl_5 @join_fields \n";
}
close($fh);