我目前正在制作一个简单的脚本来检测人与人之间的关系。我将$ np定义为正确名词的正则表达式。 在我的第一个任务中,目标是找到显示在另一个专有名词左边的所有专有名词,其中它们之间的单词数小于固定值。我写了以下代码:
$/ = '';
my $PM = qr{\b[A-Z][\w-]*\w};
my $de = qr{d[aoe]s?};
my $s = qr{[\n ]};
my $np = qr{$PM (?: $s $PM | $s $de $s $PM )*}x;
while(<>){
while(/($np)/g){
print("$1 : ");
my @x = m/(?=(?: $s+ (?: [\w-]+ | ($np)) ){1,7})/gx;
my $y = join(", ", @x);
print("$y\n");
}
}
我希望它能在文件中打印所有专有名词,并为每一个打印出窗口中的专有名词。但是,这种情况并没有发生。 我怎样才能让它像我想的那样工作?
PS:我是一名perl新手
编辑:有些人建议添加预期的输入和输出样本。 如果我有一个包含以下文本的文件
John asked Mary to meet Anna.
然后,我希望我的脚本打印
John : Mary, Anna
Mary : Anna
Anna :
但是,在当前状态下,我会以无限循环打印逗号。
答案 0 :(得分:0)
是否需要使用正则表达式?对我来说似乎不是最好的方式。 我只是将字符串分成单词并完成。类似下面的代码。
不确定我是否正确理解您的规格。我的代码所做的是找到出现在其他专有名称左侧一定距离内的专有名称。
my $window = 3;
my %result;
while(<DATA>){
my @words = map {$_ =~ s/[[:punct:]]$//; $_} split;
my $index = $#words;
for (my $index = $#words; $index > 0; $index--) {
my $word = $words[$index];
next unless is_name($word);
my $start_index = $index - 3;
$start_index = 0 if $start_index < 0;
my $end_index = $index - 1;
$end_index = 0 if $end_index < 0;
my @neigbours = grep {is_name($_)} @words[$start_index .. $end_index];
$result{$word} = [@neigbours] if @neigbours;
}
}
sub is_name {
shift =~ /^[A-Z][\w-]*\w$/;
}
__DATA__
John asked Mary to meet Anna.
答案 1 :(得分:0)
你得到一个无限循环,因为在你进行第二次匹配后,$_
的匹配位置会再次改变。您可以在匹配前将其分配给命名变量,以避免这种情况:
while( <> ) {
my $line = $_;
while( $line =~/($np)/g ) {
...
}
}
有关详细信息,请参阅Using regular expressions in Perl和pos()。