我写了这段代码:
my $id = shift;
my $file = shift;
unless(open (INFO, $file)) { print "cant open file\n"; return 0; }
#this is how i do it - i didn't copy the code directly last time:
while(my $line = <info>)
{
if($line =~ /d\s+S+\s\Q$id\disk\d+s\d+/g)
{
print "yay i found it";
close(INFO);
return 1;
}
}
close(INFO);
return 0;
一条好的线的例子是:
2: Apple_HFS 0x123456789ABC 999.9 GB disk2s2
(因为你可以看到$ id是&#34; 0x123456789ABC&#34;)
我的问题:它不起作用 - 它会打开文件并读取线条但是机器并不好。请告诉我,我在这里失踪了什么?我想我的正则表达式是错误的,但我无法解决它。
我试过谷歌和(当然)堆栈溢出(How to evaluate a word saved in a scalar via regular expression in Perl?,Detect exact string value of scalar in regex matching,Use variable as RegEx pattern)但没有运气。 我确定我错过了一些基础知识,但这不是我的第一个正则表达式 - 只有冷杉才能有标量。
谢谢
答案 0 :(得分:2)
当前的问题是$file
是文件的名称。你打开它但从未真正读过它。
以下是对您的代码的进一步评论
收集像这样的子程序的参数是很常见的,而且更加整洁
my ($id, $file) = @_
这也具有复制值的优点,因此调用中的实际参数不太可能被修改
你应该使用open
的三参数形式和词汇文件句柄,就像这样
open my $fh, '<', $file
特别是,当子例程退出时,文件将保持打开状态,因为您已选择了全局文件句柄。当词汇句柄超出范围时隐式关闭它们
您应该使用$!
错误消息中的open
内置变量来提供有关 失败原因的信息
错误通常由裸return
表示,它返回undef
或空列表,具体取决于上下文。列表上下文中的return 0
会导致列表(0)
生成 true 值,如果它被分配给数组
除非确实需要能够一次访问所有文件,否则通常最好使用while
循环逐行读取和处理它
/g
正则表达式匹配修饰符用于查找字符串中所有出现的模式。如果你想要做的就是检查模式是否
你的正则表达式也有很多问题。如果我添加/x
修饰符,那么我可以添加空格以更好地向您显示您所编写的内容
/ d \s+ S+ \s \Q$id \d isk \d+ s \d+ /x
匹配
d
字符S
字符\Q
未终止,因此字符串的其余部分按字面匹配。如果您有\Q$id\E
,那么模式的其余部分将匹配isk
s
字符并不接近匹配您显示的记录格式。重要的是要记住,您的模式不需要匹配字符串的所有,因此您可能需要像/\b\Q$id\E\b/
这样的内容来检查您的ID是否位于某个位置两端带字边界的字符串。我没有看到像0x123456789ABC
这样的字符串出现在其他地方而且给出了误报
我认为最好的解决方案是在空白处拆分每条记录,并检查第三个字段是否与传入的ID匹配
您的子程序应如下所示
sub routine {
my ($id, $file) = @_;
open my $fh, '<', $file or do {
warn "Unable to open '$file' for input: $!";
return;
};
while (my $line = <$fh>) {
my @fields = split ' ', $line;
if ($fields[2] eq $id) {
print "Yay! I found it!\n";
return 1;
}
}
return;
}
答案 1 :(得分:1)
而不是
my @lines = split(/\n/, $file);
试
my @lines = <INFO>;
甚至更好,
unless(open (my $INFO, "<", $file)) { print "cant open file\n"; return 0; }
while (my $line = <$INFO>)
{
# ..
}
你还忘了结束字符串的引用即。 \Q$string\E
if($line =~ /d\s+S+\s\Q$id\Edisk\d+s\d+/g)
答案 2 :(得分:0)
我认为正则表达式是错误的。我不确定你想要匹配什么,所以我根据这个例子进行了尝试:
\d+:.*S\s+\Q$id\E.+disk\d+s\d+
这将匹配:
d+:
一个数字后跟冒号
.*S\s+
“Apple_HFS”中的“S”和空格
\Q$id\E
您正在寻找的ID字符串
.+
一切都达到'磁盘'
disk\d+s\d+
diskXXXsXXX
适用于此代码段:
$id = "0x123456789ABC";
$line = "2: Apple_HFS 0x123456789ABC 999.9 GB disk2s2";
if($line =~ /\d+:.*S\s+\Q$id\E.+disk\d+s\d+/g)
{
print "yay i found it";
}