使用Perl查找文本中关键词出现的片段

时间:2014-03-20 00:48:03

标签: regex perl

我有文本文件,大约200行,每行15-20个单词。在文本的某处可能有"关键词"我感兴趣的是。我试图在Perl中使用正则表达式来查找这些关键词,以及一些周围的词(提供上下文)并打印所有结果。 (这个概念与谷歌在显示搜索结果的#14;片段"以及上下文中的单词时所做的几乎相同。)

对我来说,挑战在于,有时关键词会出现在一起,而我无法弄清楚如何让正则表达式来解决这个问题。我尝试过使用负面前瞻的各种组合,但到目前为止它还没有正常工作。

例如,假设关键词是红色绿色,文本文件有一堆没有关键词的行,然后是这样的:

  

这是一些文字。一种颜色是红色,另一种是绿色。绿色和红色都是彩虹色,但红色位于顶部,蓝色位于底部附近。

假设我想在" hit"的每一侧保留三个单词。对于上下文,这应该给出这两个片段:

  

1)一种颜色为红色,另一种颜色为绿色。绿色和红色都是颜色

     

2)在彩虹中,但红色在

关于如何做到这一点的任何想法?

4 个答案:

答案 0 :(得分:1)

这可能对您有所帮助。而不是担心其他单词之间的单词数量,使用字符数量更容易。同样,额外的"字"在每一方都更容易被视为字符,你后来将其变成文字。

use strict;
use warnings;

my $data = do {local $/; <DATA>};
my @words = qw(red green);

my $words_re = '\b(?:' . join('|', map quotemeta, @words) . ')\b';

while ($data =~ m{
    (.{0,20})   # Prefix
    ($words_re (?:.{1,20} $words_re)*)   # Keyword match, with another keyword w/i 20 characters
    (.{0,20})   # Postfix
}xg) {
    my ($prefix, $match, $postfix) = ($1, $2, $3);

    # Reduce prefix and postfix to just 3 words
    $prefix = reverse $prefix;
    for ($prefix, $postfix) {
        s/^(\S*(?:\s+\S+){0,3}).*/$1/;
    }
    $prefix = reverse $prefix;

    print "$prefix$match$postfix\n";
}

__DATA__
Here is some text. One color is red, another is green. Green and red are both colors that are in rainbows but red is at the top and blue is near the bottom.

输出:

One color is red, another is green. Green and red are both colors
in rainbows but red is at the

您可能需要使用金额字符,但这种方法可以帮助您。

答案 1 :(得分:1)

嗯,好吧,好吧,我试着让它发挥作用并想出了这个。我不知道这是否是解决此问题的最佳方式,但它似乎至少对您的示例字符串起作用。

/((\w+\W+){1,3}(red|green)(\W+\w+){1,3})/ig

我想要做的就是抓住一个单词,然后是非单词(空格,句号,逗号等)1-3次。然后查找表达式中的实际单词(红色或绿色)。最后,查找一个非单词字符,后跟一个单词字符1-3次。

对于示例字符串,它在位置提供以下匹配:

  • $var[0][1]一个·颜色·红色,·另一个·绿色
  • $var[1][1]绿色和红色·两种颜色
  • $var[2][1]在·彩虹·但是·红色·在·

所以,虽然这给了我两个实例中红色的预期结果,但绿色有点粗略。整场比赛给了我想要的东西,但是我不太确定它是否真的按照预期的方式按照个别项目来看待它。如果你有更多的数据可以使用,我会很高兴再玩一遍。

Here is a demo for you to review

答案 2 :(得分:1)

您可以尝试以下代码:

#!/usr/bin/perl

use strict;
use warnings;

my $txt = 'Here is some text. One color is red, another is green.'
        . ' Green and red are both colors that are in rainbows but'
        . ' red is at the top and blue is near the bottom.';

while ($txt =~ /(
    (?:                 # words before
        (?!(red|green)) # not followed by the keywords, group 2 is defined
        \b \w+          # a word boundary is needed to not truncate a keyword
        ([\s\pP]+)      # one or more spaces or punct symbols, group 3 is defined
    ){0,3}              # zero to three times (keywords can be at the begining)
    (?2)                # refers to the subpattern in group 2 (keywords)
    (?:                 # if other keywords are met before the 4th word
        (?: (?3) \w+ ){0,2} (?3) (?2)
    )* 
    (?: (?3) \w+ ){0,3} # zero to three words after
               )/gix) {
    print $1 . "\n";
}

在此示例中,关键字在模式中是硬编码的,但您可以将关键字放入数组中并像Miller的示例一样加入它们。您也可以使用变量作为单词数。

答案 3 :(得分:0)

Search::Tools CPAN module 就是专门用来进行这种截取的。

这是一个例子:

#!perl

use Search::Tools;
use 5.10.0;

my $full_text = "Here is some text. One color is red, another is green. Green and red are both colors that are in rainbows but red is at the top and blue is near the bottom. The color red is Bob's favorite";

my $snipper = Search::Tools->snipper( query         => 'red green',
                                      context       => 10,
                                      ignore_length => 1 );

say $snipper->snip($full_text);

哪个返回:

... color is red, another is green. Green and red are both colors ... in rainbows but red is at the top and ... near the bottom. The color red is Bob's favorite ...

该库的文档清晰,并能很好地处理边缘情况。