计算字符串匹配以及确定哪些句子匹配可以找到

时间:2011-01-31 03:31:51

标签: regex perl

我在Perl中这样做。 我有一个包含几个段落和61个句子的文本文件。 首先,我需要匹配在命令行输入的一系列单词,我完全没有遇到麻烦:

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

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

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

4:“我们讨厌选举。” 16:“狗从阳台上掉下来,受伤了。” 24:“将不会有2009秋季选举。”

在这种情况下,程序发现在包含秋季,选举或2009年的文件中计算了三个句子,其中秋季选举| 2009年是输入。

我的问题有两个: 如何计算输入出现的句子数?我对正则表达式非常缺乏经验,但我认为默认匹配会尝试匹配文件中发生的第一次出现的fall,election或2009,并且不计算每个单词的实例数和然后加起来。我有点挂在这上面,因为我完全不理解用正则表达式计算。

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

编辑:我实际上有一个完全解析的HTML文档,我正在执行此操作。如果打印,一个例子的输出是: “The Journal现在在Facebook上!在这里查看我们的页面。这是一项正在进行中的工作,我们很想收到您的反馈意见。请在我们的讨论区告诉我们您的想法,在下面发表评论或发送电子邮件给我们。通过Twitter上关注The Journal来发布新闻,内幕消息和好奇心。以下是您可能想要关注的一些供稿和作者:“

我的命令行如下所示: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]作为关键字,搜索文本文件,计算关键字出现的次数。然后,我需要说明关键字出现在哪个句子中(即完整地打印整个句子),以及句子所在的数字。

2 个答案:

答案 0 :(得分: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转义构建模式以防万一(如我的例子中,我们不希望它匹配)。

答案 1 :(得分:-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";
}

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