问题描述
我正在努力找出我在这里做错了什么。
我的代码的目标是读取文件str_CurrentValue.Split(","c)(0)
,然后使用正则表达式根据所说行的字符将每行排序为一个数组。它确实可以工作,但是我在这些警告之前得到输出:
movie_script.txt
这是代码:
Use of uninitialized value $char in string eq at filter.pl line 24,<$fh> line 13.
Use of uninitialized value $char in string eq at filter.pl line 26,<$fh> line 13.
Use of uninitialized value $char in string eq at filter.pl line 28,<$fh> line 13.
[...]
Hello,mother.
Oh. Well-- well,I,uh--
Well,uh,I think they must have popped by for something.
Mm,they-- they started following me yesterday.
我怀疑问题是一行不适合我的正则表达式,并且正在引起变量use strict;
use warnings;
my $filename = "movie_script.txt";
unless (-e $filename) {
print "Error: File does not exist.";
}
my @brian;
my @mandy;
my @followers;
open(my $fh,'<',$filename);
my $match = qr/^(\w+):(.+)$/i;
while (my $line = <$fh>) {
my $char = "";
my $scriptline = "";
if ($line) {
($char,$scriptline) = $line =~ $match;
if ($char eq "BRIAN") {
push(@brian,$scriptline);
} elsif ($char eq "MANDY") {
push(@mandy,$scriptline);
} elsif ($char eq "FOLLOWERS") {
push(@followers,$scriptline);
} else {
print($line);
}
}
}
foreach (@brian) {
print "$_\n";
}
和$char
的问题,但是我不知道如何确认是否正确,或如何找出引起问题的线。
我尝试使用$scriptline
运行Perl调试器,但是当我继续每一行时,都找不到错误。我已经尝试在`else {print($ line)}行周围设置一个断点,但是直到它到达该行时,我才能弄清楚如何运行调试器。
我的代码中是否有明显的原因导致我遇到非初始值问题?
解决方法
如果(电影)脚本中的行中没有字符说出来,则您的正则表达式将不匹配,并且$char
和$scriptline
将没有值。您将需要以某种方式跳过这些行。
有很多方法可以做到这一点,但一种方法是将match运算符移至if
条件:
if (($char,$scriptline) = $line =~ $match) {
if ($char eq "BRIAN") {
push(@brian,$scriptline);
} elsif ($char eq "MANDY") {
push(@mandy,$scriptline);
} elsif ($char eq "FOLLOWERS") {
push(@followers,$scriptline);
} else {
print($line);
}
}
该脚本现在将忽略所有非对话框行,这些特定的转换成员说的push
行以及其他人说的打印行。
考虑让Perl告诉您问题出在哪里。
if ($line) {
if (my ($char,$scriptline) = $line =~ $match) {
# Your existing code here
} else {
warn "Line [$line] doesn't match the regex [$match]\n";
}
请注意,我还将$char
和$scriptline
的声明移到了最小的范围内。没必要提前声明它们或预先填充它们(因为您将在匹配行中覆盖该数据)。
未初始化警告的原因是文件中的某些行与正则表达式不匹配,但是您仍使用变量。解决方案是,通过使用if
语句检查正则表达式不匹配时,不使用变量,如下例所示。
一些要点。
- 考虑使用散列而不是许多数组来存储行。这将使脚本可重复使用且灵活。
- 不必对文件名进行硬编码。您只需在命令行上提供文件名,然后使用菱形运算符
<>
来读取文件:while (my $line = <>) { ....
并使用
运行它$ lines.pl movie_script.txt
-
您不需要为与正则表达式匹配的内容添加变量。由于您在正则表达式中使用括号
()
,因此已经解决了这一问题。匹配项存储在预定义的变量$1
和$2
中。 -
您将捕获行中的前导空格,可以通过在第二个括号前面的正则表达式中添加
\s*
来解决此问题。 -
您正在使用正则表达式中的
/i
修饰符,该修饰符未使用,因为正则表达式中没有任何字母。 (例如,如果您进行了/foo/i
,它将与FOO
相匹配) -
您可以使用
/s
修饰符允许.+
匹配换行符,因此不必稍后再添加回去。
您的程序是一个非常基本的,典型的perl单行代码,不需要复杂。在此示例中,我使用Data::Dumper
模块向您展示生成的数据结构如何:
use strict;
use warnings;
use Data::Dumper;
$Data::Dumper::Useqq = 1; # show newline in Dumper print
my %lines;
my $match = qr/^(\w+):\s*(.+)/s; # remove unused /i,add /s
while (my $line = <DATA>) {
if ($line =~ $match) { # Check before you use the variables
push @{$lines{$1}},$2; # Store the matches in your hash
} # <--- if you want to do something with unmatched lines,use else
}
print for (@{$lines{BRIAN}});
print Dumper \%lines;
__DATA__
BRIAN: Hello,mother.
MANDY: Hi
BRIAN: Oh. Well-- well,I,uh--
FOLLOWERS: Hello
(我使用<DATA>
文件句柄在程序中模拟您的文本文件,只需将<DATA>
替换为<>
)
该程序将输出
Hello,mother.
Oh. Well-- well,uh--
$VAR1 = {
"BRIAN" => [
"Hello,mother.\n","Oh. Well-- well,uh--\n"
],"MANDY" => [
"Hi\n"
],"FOLLOWERS" => [
"Hello\n"
]
};
它将与不同的文件名一起使用,它将捕获任何命名字符的行,而不仅仅是您硬编码的3个字符。
,以下perl脚本
- 采用文件名进行处理或使用默认文件名“ movie_script.txt”
- 在文件中查找模式
CHARACTER: LINE
,并用数据填充哈希值 - 对字符进行排序并打印其行
use strict;
use warnings;
use feature 'say';
my $filename = shift || 'movie_script.txt';
my $match = qr/^(\w+):(.+)$/i;
my %script;
open my $fh,'<',$filename
or die "Couldn't open $filename";
while(<$fh>) {
next if /^\s*\Z/;
push @{$script{$1}},$2 if /$match/;
}
close $fh;
for my $char ( sort keys %script ) {
say $char;
say "\t$_" for @{$script{$char}};
}
输出
BRIAN
Oh. Well-- well,uh--
Well,uh,I think they must have popped by for something.
Mm,they-- they started following me yesterday.
FOLLOWERS
The Messiah! The Messiah! Show us the Messiah!
The Messiah!
The Messiah! The Messiah!
Show us the Messiah! The Messiah! The Messiah! Show us the Messiah!
MANDY
Don't you 'hello mother' me. What are all those people doing out ther e?!
Come on! What have you been up to,my lad?!
'Popped by'?! 'Swarmed by',more like! There's a multitude out there!
Well,they can stop following you right now. Now,stop following my son! You ought to be ashamed of yourselves.
The who?
Huh,there's no Messiah in here. There's a mess,all right,but no Me ssiah. Now,go away!
Ooooh.
Now,you listen here! He's not the Messiah. He's a very naughty boy! Now,go away!
RIAN
Hello,mother.