2011-01-31 62 views
0

我在Perl中这样做。 我有一个文本文件,其中包含几个段落和61个句子。 首先,我需要匹配一系列的命令行输入的话,我有过一次这样做没有问题:计算字符串匹配以及确定哪些语句匹配可以在

my $input = $ARGV[0]; 
$file =~ m/$input/gi; 

不幸的是,有一些wrinkles- 1.输入可为多个项目和 2.多个项目可以在不同的行。

我会告诉你一个例子: 3句匹配模式“秋|选| 2009”。这些句子是:

4:“我们讨厌选举。” 16:“狗从阳台坠落时受伤。” 24:“2009年秋季没有选举。”选| | 2009年是输入

在这种情况下,程序发现,无论是包含秋天,选举或2009年,在秋天的文档中数三句话。

我的问题是双重的: 如何计算句子的输入出现在多少?我对regex很没有经验,但我会认为默认匹配会尝试匹配文件中发生的第一次出现的秋天,选举或2009年,也不会计算每个单词有多少个实例,以及然后添加它们。我有点担心,因为我不明白正则表达式。

我的问题的第二部分涉及如何首先找到哪个句子输入被找到(即出现在第4行的选举)以及如何提取输入位于的整个句子。我认为这将是使用第一个if完成:如果字符串中有匹配的输入,则新的标量等于文本文件=〜替换?这句话......我完全不确定。

编辑:我实际上有一个完全解析的HTML文档,我正在执行此操作。如果打印出来,一个例子的输出是: “The Journal is now on Facebook!The view is this in progress,we're hungry for your feedback。因此,让我们知道您对我们的讨论的看法董事会,下面的评论或给我们发电子邮件。通过关注Twitter上的杂志获取重大新闻,内部信息和好奇心以下是您可能需要遵循的一些Feed和作者:“

我的命令行如下所示:perl WebScan.pl信息|作家WebPage000.htm

我有,如前面提到的通过网页解析并去除所有标签,只留下文字。现在,我必须找到输入,在这种情况下是“信息”或“作家”。我必须找出这些文件中发生了多少次(所以2),以及它们出现在哪个句子中(分别是5和6)。我会到目前为止告诉你我的代码:

use strict; 
use warnings; 
my $file; 
open (FILENAME, $ARGV[1]); 
$file = do { local $/; <FILENAME> }; 

$file =~ s{ 
    <    # open tag 
    (?:    # open group (A) 
    (!--) |  # comment (1) or 
    (\?) |  # another comment (2) or 
    (?i:   # open group (B) for /i 
     (   #  one of start tags 
     SCRIPT | #  for which 
     APPLET | #  must be skipped 
     OBJECT | #  all content 
     STYLE  #  to correspond 
    )   #  end tag (3) 
    ) |   # close group (B), or 
    ([!/A-Za-z]) # one of these chars, remember in (4) 
)    # close group (A) 
    (?(4)   # if previous case is (4) 
    (?:   # open group (C) 
     (?!   #  and next is not : (D) 
     [\s=]  #  \s or "=" 
     ["`']  #  with open quotes 
    )   #  close (D) 
     [^>] |  #  and not close tag or 
     [\s=]  #  \s or "=" with 
     `[^`]*` | #  something in quotes ` or 
     [\s=]  #  \s or "=" with 
     '[^']*' | #  something in quotes ' or 
     [\s=]  #  \s or "=" with 
     "[^"]*"  #  something in quotes " 
    )*   # repeat (C) 0 or more times 
    |    # else (if previous case is not (4)) 
    .*?   # minimum of any chars 
)    # end if previous char is (4) 
    (?(1)   # if comment (1) 
    (?<=--)  # wait for "--" 
)    # end if comment (1) 
    (?(2)   # if another comment (2) 
    (?<=\?)  # wait for "?" 
)    # end if another comment (2) 
    (?(3)   # if one of tags-containers (3) 
    </   # wait for end 
    (?i:\3)  # of this tag 
    (?:\s[^>]*)? # skip junk to ">" 
)    # end if (3) 
    >    # tag closed 
}{}gsx;   # STRIP THIS TAG 
$file =~ s/&nbsp//gi; 
$file =~ s/&#160//gi; 
$file =~ s/;//gi; 

$file =~ s/[\h\v]+/ /g; 

my $count = $file =~ s/((^|\s)\S)/$2/g; 
my $sentencecount = $file =~ s/((^|\s)\S).*?(\.|\?|\!)/$1/g; 

print "Input file $ARGV[1] contains $sentencecount sentences and $count words."; 

所以,我需要Perl来,使用$ ARGV [0]为关键词,通过文本文件进行搜索,计算的时候出现的关键字数量。然后,我需要说明关键字出现在哪个句子(即全部打印整个句子)以及句子所在的编号。

回答

-1

编辑以匹配更新的问题

好吧,让我开始一个真理:不要试图自己来解析HTML。 HTML::TreeBuilder是你的朋友。

对于正则表达式,perlfaq6是一个很好的知识来源。

以下示例使用以下语法:perl WebScan.pl --regex="information|writers" --filename=WebPage000.htm

它将打印段落及其匹配的列表。

#!/usr/bin/perl 
use warnings; 
use strict; 

use HTML::TreeBuilder; 
use Data::Dumper; 
use Getopt::Long; 

my @regexes; 
my $filename; 
GetOptions('regex=s' => \@regexes, 'filename=s' => \$filename); 

my $tb = HTML::TreeBuilder->new_from_file($filename); 
$tb->normalize_content; 

my @patterns = map { qr/$_/ } @regexes; 

my @all; 
foreach my $node ($tb->find_by_tag_name('p', 'pre', 'blockquote')) { 
    my $text = $node->as_text; 
    my @matches; 
    foreach my $r (@patterns) { 
     while ($text =~ /$r/gi) { 
      push @matches, $&; 
     } 
    } 
    push @all, { paragraph => $text, matches => \@matches } if @matches; 
} 

foreach (@all) { 
    print "Paragraph:\n\t$_->{paragraph}\nMatches:\n\t", join(', ', @{$_->{matches}}), "\n"; 
} 

希望这可以指出你在正确的方向。

+0

我编辑了我的问题,希望能让事情更清楚。你的代码做的事情与我想要的非常相似,我只是不知道如何实现它。 – Sheldon 2011-01-31 04:39:24

1

您不清楚您的句子是否有分隔符(或者您是否有一些分隔条件)。如果是这样,如果明白你的问题所在,你可以做一些事情是这样的:

@words = qw/hi bye 2009 a*d/; 
@lines = ('Lets see , hi ', 
' hi hi hi ', 
' asdadasdas ', 
'a2009a', 
'hi bye'); 

$pattern=""; 
foreach $word (@words) { 
    $pattern .= quotemeta($word) . '|'; 
} 
chop $pattern; # chop last | 
print "pattern='$pattern'\n"; 

$cont = 0; 
foreach $line (@lines) { 
    $cont++ if $line =~ /$pattern/o; 
} 

printf "$cont/%d lines matched\n",scalar(@lines); 

我建立与quotemeta模式逃逸,以防万一有在的话一些特殊字符(如在我的例子中,我们不希望它匹配)。