首先,感谢您在此问题上给我的任何帮助。我有一个单词列表,在下面的例子中它是一个颜色列表。我们称之为WORD_LIST_1。 我想计算每个单词出现在文本正文中的次数。我可以使用简单的正则表达式来完成此操作。 但是,我有另一个捕获上下文的单词列表。在下面的示例中,上下文是宠物列表。我们称之为WORD_LIST_2。 我想计算WORD_LIST_1中每个单词在WORK_LIST_2中任何单词的X个单词内的次数。 我的策略是使用正则表达式将WORD_LIST_1单词的匹配提取到数组中,然后创建哈希,计算每个单词在此数组中的次数。 当上下文单词(WORD_LIST_2)跟随WORD_LIST_1单词时,我可以轻松完成。 但是,当WORD_LIST_2单词出现在WORD_LIST_1单词之前时,我遇到了问题,特别是当有多个WORD_LIST_2单词时。
以下是代码。
#!/usr/bin/perl -w
#use strict;
@colors = ("red", "blue", "green", "brown");
$WORD_LIST_1 = join("|",@colors);
@pets = ("cat","dog","bird","fish");
$WORD_LIST_2 = join("|",@pets);
#$text1 = "The red haired dog quickly and sharply ran away from the blue nosed cat.";
#$text1 = "The green spotted cat drinks blue water.";
#$text1 = "The brown feathered, green beaked bird flew away.";
$text1 = "The fish with blue fins and red tails.";
@finds = ();
$within_N_words = 4;
@finds = $text1 =~ m/\b(?=($WORD_LIST_1)\W+(?:\w+\W+){0,$within_N_words}?(?:$WORD_LIST_2))\b|\b(?=(?:$WORD_LIST_2)\W+(?:\w+\W+){0,$within_N_words}?($WORD_LIST_1))\b/gi;
@finds = grep defined, @finds;
print "\n\n", join("|", @finds), "\n\n";
请注意,第四条$ text1行的下面有蓝色和红色。但它只会返回"蓝色"并且不会返回" red"太。我检查了注释掉的前三个句子,看起来效果很好。
我的方法基于此页面:http://www.regular-expressions.info/near.html
我曾考虑过考虑使用积极的后视,但我需要在后面看一下可变长度。
我考虑过翻转整个文本字符串和正则表达式,然后再次搜索。但这可能导致重复计算。
我还考虑过使用某种循环在各个常规扩展中搜索每个WORD_LIST_1单词。 但是,这需要花费大量时间在我的真实数据上,因为实际的WORD_LIST_1列表是500个左右的单词而且我有多个长度文本的主体我想要搜索。
另外两个旁注:
(1)上面的正则表达式偶尔会将空元素返回到@finds数组中。我无法弄清楚原因。我的工作是使用grep定义的行。解决这个问题的正确方法是什么。相反,为什么我的正则表达式返回空白元素?
(2)我还在学习"适当的"使用PERL的方法。我在这个例子中评论了使用严格,因为我不相信我使用perl的上下文它会产生影响。我相信有人可以告诉我为什么这对我来说是错的。好的PERL程序员似乎总是告诉我,我不应该使用perl代码而不使用严格,但没有人说服我这是我需要担心的事情。但是,我愿意学习。
答案 0 :(得分:1)
好吧,首先关闭 - 您提供的文字......看起来red
首先距离fish
超过4个字?
但是失败了 - 我认为问题是因为你的正则表达式“消耗”第一场比赛的文字所以它不是第二场比赛。
在此,您开始遇到正则表达式引擎的限制 - http://www.regular-expressions.info/keep.html
使用单个正则表达式进行搜索有多重要?请记住,虽然正则表达式看起来非常简洁,但它很难阅读并且计算成本很高。
因此,我建议您分割模式的初步建议并不像听起来那么糟糕 - 为了匹配第二个示例中的“红色”和“蓝色”,您需要考虑' ll允许重复匹配。
E.g。
fish cat red red blue blue
应该到达多少次点击?您可以使用类似哈希的东西来计算单词的重复数,并重复删除“关系”:
my %matches = (
$text1 =~ m/
\b
($WORD_LIST_2)
\W+
(?:\w+\W+){0,$within_N_words}?
($WORD_LIST_1)\b
/gix
);
print Dumper \%matches;
我们匹配哈希,因为当我们'插入'配对词时,我们得到键值对:
$VAR1 = {
'fish' => 'blue'
};
但是知道它可能是有用的 - 你可以在perl中使用qr
来“编译”一个正则表达式并看看你实际上最终得到了什么。
在你的例子中:
print qr /\b(?=($WORD_LIST_1)\W+(?:\w+\W+){0,$within_N_words}?(?:$WORD_LIST_2))\b|\b(?=(?:$WORD_LIST_2)\W+(?:\w+\W+){0,$within_N_words}?($WORD_LIST_1))\b/;
(?^:\b(?=(red|blue|green|brown)\W+(?:\w+\W+){0,4}?(?:(?^:cat|dog|bird|fish)))\b|\b(?=(?:(?^:cat|dog|bird|fish))\W+(?:\w+\W+){0,4}?(red|blue|green|brown))\b)
第一种模式根本不匹配。 第二个确实,但只有一次,因为它“吃掉”现有的模式。
my @finds2 = ( $text1 =~ m/\b(?:$WORD_LIST_2)\W+(?:\w+\W+){0,$within_N_words}?($WORD_LIST_1)\b/gi )
查找blue
。删除'nongreedy'修饰符,它会找到red
。但是因为你的模式已“吃掉”前面的位,所以它与g
修饰符不能匹配两次。
我不认为 perl会在该上下文中支持多重匹配,因为如果你考虑一下,所需的比较数量会很快变大。
我还会提供:
x
修饰符,以便在它们变长时编写正则表达式。 这样的事情:
my @pets = qw (cat dog bird fish );
my $WORD_LIST_2 = join( "|", map {quotemeta} @pets );
$WORD_LIST_2 = qr/$WORD_LIST_2/;
my @finds2 = (
$text1 =~ m/
\b
(?:$WORD_LIST_2)
\W+
(?:\w+\W+){0,$within_N_words}?
($WORD_LIST_1)\b
/gix
);
For 1:因为你的捕获是交替的两侧,但只有一个可以匹配。所以那个不返回undef
的那个。将您的模式拆分为两个,您将不会遇到此问题。或者使用?|
进行分支重置。 http://www.effectiveperlprogramming.com/2010/09/use-branch-reset-grouping-to-number-captures-in-alternations/
2:Why use strict and warnings?
所以我建议最终得到类似的东西:
#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
my @colors = qw ( red blue green brown );
my $WORD_LIST_1 = join( "|", map {quotemeta} @colors );
$WORD_LIST_1 = qr/$WORD_LIST_1/;
my @pets = qw (cat dog bird fish );
my $WORD_LIST_2 = join( "|", map {quotemeta} @pets );
$WORD_LIST_2 = qr/$WORD_LIST_2/;
my $within_N_words = 4;
while ( my $text1 = <DATA> ) {
print $text1;
my %matches = (
$text1 =~ m/(?|
\b #word break
($WORD_LIST_2)
\W+
(?:\w+\W+){0,$within_N_words}? #nongreedy 0-N 'words'.
($WORD_LIST_1)
\b
|
\b
($WORD_LIST_1)
\W+
(?:\w+\W+){0,$within_N_words}?
($WORD_LIST_2)
\b
)
/gix
);
print Dumper \%matches;
}
__DATA__
The red haired dog quickly and sharply ran away from the blue nosed cat.
The green spotted cat drinks blue water.
The brown feathered, green beaked bird flew away.
The fish with blue fins and red tails.
这给了我们两个词和背景:
The red haired dog quickly and sharply ran away from the blue nosed cat.
$VAR1 = {
'blue' => 'cat',
'red' => 'dog'
};
The green spotted cat drinks blue water.
$VAR1 = {
'green' => 'cat'
};
The brown feathered, green beaked bird flew away.
$VAR1 = {
'brown' => 'bird'
};
The fish with blue fins and red tails.
$VAR1 = {
'fish' => 'blue'
};
(您可以使用values
来提取单词)。