简单的Perl正则表达式解析器

3

嘿,我正在开发一个非常基础的解析器。我几乎可以确定我的正则表达式是正确的,但是数值似乎没有被存储在我的$1$2中。我做错了什么吗?我只是想要一些提示来改进我的代码。谢谢任何建议!另外,我是Perl的新手,如果我做错了什么,我希望能够开个好头,养成良好的习惯。

文件中的示例行:

Sat 02-August-2008 20:47 - 123.112.3.209 - "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1;

我只是从时间中获取小时数。
foreach my $line (@lines)
{   
my $match =~ /\d\d-\w+-\d{4} (\d)(\d):\d\d/;

if( $1 == 0)
{
    $times[$2] = $times[$2] + 1;
}
else
{   
    my $time = $1.$2;
    $times[$time] = $times[$time]+ 1;
}
 }


print "\n";
for(my $i=0;$i<24;$i++)
{
print "$i: $times[$i]\n";
}

1
你在尝试解析什么?你知道,我们这里可不是通灵的。 - JesperE
@jesperE正在使用示例进行编辑。 - PFranchise
我知道我正在从文件中获取这些行。我之前测试过,并能够在循环内重新打印每一行。 - PFranchise
3个回答

7
如果您想匹配$line,代码应该是这样的。
$line =~ /\d\d-\w+-\d{4} (\d)(\d):\d\d/;

看这里


嗯,我做了那个更改,但仍然不起作用。我的$1和$2似乎是空的。我感谢你的提示,我认为你可能是对的,它必须是$line,但由于我最多只是Perl的初学者,我不确定。 - PFranchise
2
我从示例行中得到了2和0,正如预期的那样。你确实把$line前面的my去掉了吗? - Brian Rasmussen
哈哈,谢谢你看穿了我的新手状态。我很感激你抽出时间来帮助我。祝你晚安。 - PFranchise

3

你能给出一些你想匹配的模式的例子吗?否则我无法判断你的正则表达式是否匹配了你的模式。不过你可以对你的代码进行一些改进:

首先,如果你想使用 $1、$2 等,务必测试一下匹配是否成功。

if($match =~ /\d\d-\w+-\d{4} (\d)(\d):\d\d/) {

    if( $1 == 0)
    {
        $times[$2] = $times[$2] + 1;
    }
    else
    {   
        my $time = $1.$2;
        $times[$time] = $times[$time]+ 1;
    }
} else {
    warn "no match!\n";
}

其次,始终使用“-w”开关。在这种情况下,您可能会收到有关未初始化$1和$2的警告消息,因为匹配失败:

#!/usr/bin/perl -w

谢谢你的建议,我非常感激。另一个人的答案解决了我的问题,所以没有必要再深入研究我的问题。但是,我会将你的建议融入到我的代码中。祝你晚上愉快。 - PFranchise

1

首先,如果你是Perl的新手,其中一个优点就是CPAN和那里的许多解决方案。不要重复造轮子!

有一个很棒的模块叫做Date::Parse,它可以为您解析时间部分。然后,您唯一需要解决的正则表达式问题就是将您的行中的时间部分分离出来。

根据您提供的单行样本,以下代码可以实现这一点:

use strict;
use warnings;

use Date::Parse;

my $line="Sat 02-August-2008 20:47 - 123.112.3.209 - \"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1;";
my $tmpart;

if ($line=~ /^(.*\d+:\d+) -/) {
    $tmpart=$1;

    print "Time part = $tmpart\n";

    my $time=str2time($tmpart);
    my ($ss,$mm,$hh,$day,$month,$year,$zone) = strptime($tmpart);

    $year+=1900;
    $month+=1;

    print "Unix time: $time\n";
    print "Parsed time: $month/$day/$year $hh:$mm:$ss  \n\n";
} 
else {
   warn "no match!\n";
}   

这将返回一个Unix时间戳,然后可以轻松处理。或者(如所示)您可以解析时间的各个组件。


这行代码存在一些问题:my $tmpart = $1 if $line=~ /^(.*\d+:\d+) -/; 如果你的正则表达式匹配失败,$tmpart 将是未定义的,你会收到一堆警告和错误的结果。 - daotoad
有些错误逻辑代码很容易修复。搞定了!感谢指出。 - dawg

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接