代码之家  ›  专栏  ›  技术社区  ›  Michael Mao

如何使用Perl用regex解析指定的格式化文本?

  •  1
  • Michael Mao  · 技术社区  · 14 年前

    问题摘要:

    如何在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)表示页面及其对应的pagerank。

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

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

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

    如果你还在这一页,让我解释一下为什么我在这里问这个问题:

    除了“结果7/10”,我什么也没有得到,uni也没有评论。

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

    所以,我希望Perl专家至少能指导我正确地解决这个问题。我愚蠢的解决方案是“通用的”,可能会在爪哇,C等,我相信这甚至不接近Perl的性质。

    如果可能的话,请让我知道解决方案的级别,就像我需要通过“学习Perl==>编程Perl==>掌握Perl”来达到那样:)

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

    编辑1:

    我还有一个问题要问,但没有回答。 here 它描述了我大学的情况:(

    2 回复  |  直到 14 年前
        1
  •  3
  •   Pedro Silva    14 年前

    这就是你的意思吗?regex基本上有三个捕获组(由 () s)。它应该捕获一个数字,后跟 = : (这是包装字符类的捕获组 [] ,匹配其中的任何字符),后跟另一个数字。

    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 如果可以的话。非常…彻底。

        2
  •  1
  •   daotoad    14 年前

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

    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;
    

    这段代码与佩德罗·席尔瓦的主要区别在于,我的代码更加冗长,而且它还可以正确处理来自一个页面的多个链接。例如,我的代码保留了第1页中链接的所有值。佩德罗的密码只剩下最后一个。