2010-10-18 48 views
4

我是Perl的全新手,但是我听说它对于解析文件非常好,所以我想过给它一个旋转。如何用Perl解析文件的一部分?

我有了下面的示例信息的文本文件:

High school is used in some 
parts of the world, particularly in 
Scotland, North America and Oceania to 
describe an institution that provides 
all or part of secondary education. 
The term "high school" originated in 
Scotland with the world's oldest being 
the Royal High School (Edinburgh) in 
1505. 

The Royal High School was used as a 
model for the first public high school 
in the United States, the English High 
School founded in Boston, 
Massachusetts, in 1821. The precise 
stage of schooling provided by a high 
school differs from country to 
country, and may vary within the same 
jurisdiction. In all of New Zealand 
and Malaysia along with parts of 
Australia and Canada, high school is 
synonymous with secondary school, and 
encompasses the entire secondary stage 
of education. 

====================================== 
Grade1 87.43% 
Grade2 84.30% 
Grade3 83.00% 
===================================== 

我想分析该文件,并只获得数字信息。我 看着正则表达式,我想我会使用类似

if (m/^%/) { 
    do something 
} 
else { 
    skip the line 
} 

但是,我真正想要做的是保持对 左侧履带的变量,并存储在该变量的数值。所以,在解析文件 后,我真的希望有以下变量 将%值存储在它们中。原因是,我想要 创建不同等级的饼图/条形图。

Grade1 = 87.43 Grade2 = 84.30

...

难道你会建议我应该看什么方法呢?

+0

大家好:但是,如果您遇到与困难(有时DWIMmery可能得到的方式),也可以明确地在读取文件中的行由行保持状态。不过,我必须承认错误我做了,我提到,说 Grade1 - 80% Grade2 - 80% 等。 的问题是你的解决方案利用了“级”的作为选择的标准正则表达式。但是,这只是一个文件。我的大多数其他文件,有他们个人的名字,如: 麦克80% 肖恩·60% 杰森44% 所以使得它更棘手现在使用过滤器... – c0d3rs 2010-10-18 16:32:50

回答

6

你需要一个正则表达式。类似以下内容应该可以工作

while (<>) { 
    /(Grade[0-9]+)\s*([0-9]+\.[0-9]+)/; 
    $op{$1} = $2; 
} 

作为过滤器。 op散列将存储等级名称和分数。这比自动实例化变量更可取。

+0

我有一个错字在我的正则表达式。我现在修好了。 – 2010-10-18 16:27:03

-1

创建动态变量名称可能不会帮助您制作图表;使用数组几乎肯定是一个更好的主意。

但是,如果你真的认为你想这样做:

while (my $line = <$your_infile_handler>){ 
    if ($line =~ m/(.*) = ([0-9.]*)){ 
     $$1 = $2; 
    } 
} 

应该做到这一点。

+0

嗨,你是对的。我一直在寻找一些可以从数据生成图形的脚本,比如GD:(http://www.ibm.com/developerworks/library/os-perlgdchart/),他们提到创建一个数组,例如Data [] [ ]。但我并不完全知道如何通过解析文件来填充该数组。我要给这一些尝试,并回来困难,我有... – c0d3rs 2010-10-18 16:35:26

2

你想使用散列。像这样的应该做的伎俩:

my %grades =(); # this is a hash 
open(my $fh, "grade_file.txt") or die $!; 
while(my $line = <$fh>) { 
    if(my($name, $grade) = $line =~ /^(Grade\d+)\s(\d+\.\d+\%)) { 
     $grades{$name} = $grade; 
    } 
} 
close($fh); 

你的%grades哈希将包含名称和成绩对。 (访问它像my $value = $grades{'Grade1'}

也只有一个音符。这种语言被称为“Perl的”,而不是“PERL”。很多人在Perl社区生气吧:-)

+0

大家好 - 谢谢你的答复。不过,我必须承认错误我做了,我提到,说 Grade1 - 80% Grade2 - 80% 等。 的问题是你的解决方案利用了“级”的作为选择的标准正则表达式。但是,这只是一个文件。我的大多数其他文件,有他们个人的名字,如: 麦克80% 肖恩·60% 杰森44% 因此,它使我 – c0d3rs 2010-10-18 16:26:16

+0

此外,谢谢你让我知道Perl的!我不会再犯这个错误;)。 – c0d3rs 2010-10-18 16:30:07

3

如果你能保证你的兴趣点两个嵌套=秒(而没有奇数在给定文件中的这些分界线),触发器运营商这里是一个方便的事情之间:

use strict; # These two pragmas go a long, ... 
use warnings; # ... long way in helping you code better 

my %scores; # Create a hash of scores 

while (<>) { # The diamond operator processes all files ... 
       # ... supplied at command-line, line-by-line 

    next unless /^=+$/ .. /^=+$/; # The flip-flop operator used ... 
            # ... to filter out only 'grades' 

    my ($name, $grade) = split; # This usage of split will break ... 
            # ... the current line into an array  

    $scores{$name} = $grade;  # Associate grade with name 
} 
+0

+1提到触发器操作符。有趣。 – 2010-10-19 06:03:31

0

为例见Zaid's answer使用触发器操作符(这是我会推荐的)。 - 感谢您的答复

#!/usr/bin/perl 

use strict; use warnings; 

my %grades; 
my $interesting; 

while (my $line = <DATA>) { 
    if (not $interesting and $line =~ /^=+\s*\z/) { 
     $interesting = 1; 
     next; 
    } 
    if ($interesting) { 
     if ($line =~ /^=+\s*$/) { 
      $interesting = 0; 
      next; 
     } 
     elsif (my ($name, $grade) = $line =~ /^(\w+)\s+(\d+\.\d+%)/) { 
      # Keep an array in case the same name occurs 
      # multiple times 
      push @{ $grades{$name} }, $grade; 
     } 
    } 
} 

use YAML; 
print Dump \%grades;