如何使用Perl用正则表达式解析指定的格式化文本?

时间:2010-07-20 23:29:29

标签: regex perl

问题摘要:

如何在Perl中将文本文件解析为两个“哈希”。一个商店的键值对取自(X = Y)部分,另一个来自(X:Y)部分?

1=9  
2=2  
3=1  
4=6  
2:1  
3:1  
4:1  
1:2
1:3  
1:4  
3:4  
3:2

它们保存在一个文件中,只有两个数字之间的符号表示差异。

=============================================== ================================

我在上学期花了大约30个小时学习Perl,并设法以“先头,特别,丑陋”的方式完成我的Perl任务。

刚刚收到我对本节的结果为7/10,坦率地说,我对此并不满意,特别是因为它让我想起了使用正则表达式来处理格式化数据的可怜记忆,这个规则是这样的:

1= (the last digit in your student ID,or one if this digit is zero)  
2= (the second last digit in your student ID,or one if this digit is zero)
3= (the third last digit in your student ID, or one if this digit is zero)
4= (the forth last digit in your student ID, or one if this digit is zero)

2:1 
3:1  
4:1  
1:2  
1:3  
1:4  
2:3 (if the last digit in your student ID is between 0 and 4) OR
    3:4 (if the last digit in your student ID is between 5 and 9)
3:2 (if the second last digit in your student ID is between 0 and 4) OR
    4:3 (if the second last digit in your student ID is between 5 and 9)

An example of the above configuration file: if your student ID is 10926029, it has to be:

1=9  
2=2  
3=1  
4=6  
2:1  
3:1  
4:1  
1:2
1:3  
1:4  
3:4  
3:2

该任务是关于Pagerank计算,该算法是简化的,所以我在5分钟内得出了该部分的答案。然而,文本解析部分花了我很多时间。

文本的第一部分(Page = Pagerank)表示页面及其相应的页面。

第二部分(FromNode:ToNode)表示两页之间链接的方向。

为了更好地理解,请访问我的网站并查看需求文件和我的Perl脚本here

脚本中有大量的评论,所以我认为看到我的解决方案有多愚蠢并不难:(

如果您仍在此页面上,请让我证明为什么我在SO中提出这个问题:

我没有别的,只有“结果7/10”而没有来自uni的评论。

我不是在为大学学习,我是在为自己学习。

所以,我希望Perl大师能够至少指导我解决这个问题的正确方向。我的愚蠢解决方案有点“通用”,很可能适用于Java,C#等。我相信它甚至不会接近Perl的本质。

如果可能的话,请告诉我解决方案的级别,比如我需要通过“学习Perl ==>编程Perl ==> Master Perl”来实现:)

提前感谢任何提示和建议。

编辑1:

我发布了另一个问题,但已关闭here,其中描述的内容非常类似于我的单身内容:(

2 个答案:

答案 0 :(得分:3)

这是什么意思?正则表达式基本上有三个捕获组(由() s表示)。它应该捕获一个数字,然后是=:(这是包含字符类[]的捕获组,它匹配其中的任何字符),然后是另一个数字。< / p>
my ( %assign, %colon );

while (<DATA>) {
    chomp;                     
    my ($l, $c, $r) = $_ =~ m/(\d)([=:])(\d)/;

    if    ( q{=} eq $c ) { $assign{$l} = $r; }
    elsif ( q{:} eq $c ) { $colon{$l}  = $r; }
}        

__DATA__
1=9  
2=2  
3=1  
4=6  
2:1  
3:1  
4:1  
1:2
1:3  
1:4  
3:4  
3:2

至于建议,如果可以,请抓取Mastering Regular Expressions的副本。这非常彻底。

答案 1 :(得分:1)

好吧,如果您不想验证对数据文件的任何限制,您可以非常轻松地解析这些数据。主要问题在于选择适当的结构来存储数据。

use strict;
use warnings;

use IO::File;

my $file_path = shift;  # Take file from command line

my %page_rank;
my %links;

my $fh = IO::File->new( $file_path, '<' )
    or die "Error opening $file_path - $!\n";

while ( my $line = $fh->readline ) {
    chomp $line;

    next unless $line =~ /^(\d+)([=:])(\d+)$/; # skip invalid lines

    my $page      = $1;
    my $delimiter = $2; 
    my $value     = $3;


    if( $delimiter eq '=' ) {

        $page_rank{$page} = $value;
    }
    elsif( $delimiter eq ':' ) {

        $links{$page} = [] unless exists $links{$page};

        push @{ $links{$page} }, $value;
    }

}

use Data::Dumper;
print Dumper \%page_rank;
print Dumper \%links;

此代码与Pedro Silva不同的主要方式是我的代码更加冗长,并且它还可以正确处理来自一个页面的多个链接。例如,我的代码保留了第1页链接的所有值。佩德罗的代码丢弃了除最后一个之外的所有值。