Perl替换运算符可以匹配数组中的元素吗?

时间:2010-10-27 06:00:11

标签: perl

我有一个像这样的数组

my @stopWords = ("and","this",....)

我的文字在这个变量中

my $wholeText = "....and so this is...."

我希望在标量wholeText中匹配我的stopWords数组的每个元素的每一个匹配项,并用空格替换它。

这样做的一种方法如下:

foreach my $stopW (@stopWords)
{
   $wholeText =~ s/$stopW/ /;
}

这可以工作并替换所有停用词的每次出现。我只是想知道,如果有更短的方法。

像这样:

$wholeText =~ s/@stopWords/ /;

以上似乎并不奏效。

6 个答案:

答案 0 :(得分:7)

虽然各种基于map / for的解决方案正常工作,但它们也会针对每个停用词分别对字符串进行正则表达式处理。虽然在给出的示例中这没什么大不了的,但随着目标文本和禁用词列表的增长,它可能会导致严重的性能问题。

Jonathan Leffler和Robert P在正确的轨道上提出了将所有停用词混合成一个正则表达式的建议,但是将所有停用词简单地join转换为单一的替换是一种粗略的方法,并再次如果禁用词列表很长,则效率低下。

输入Regexp::Assemble,这将为您构建一个更“智能”的正则表达式,以便同时处理所有匹配项 - 我已经使用它来实现最佳效果,最多可以检查1700个左右的单词:

#!/usr/bin/env perl

use strict;
use warnings;
use 5.010;

use Regexp::Assemble;

my @stopwords = qw( and the this that a an in to );

my $whole_text = <<EOT;
Fourscore and seven years ago our fathers brought forth
on this continent a new nation, conceived in liberty, and
dedicated to the proposition that all men are created equal.
EOT

my $ra = Regexp::Assemble->new(anchor_word_begin => 1, anchor_word_end => 1);
$ra->add(@stopwords);
say $ra->as_string;

say '---';

my $re = $ra->re;
$whole_text =~ s/$re//g;
say $whole_text;

哪个输出:

\b(?:t(?:h(?:at|is|e)|o)|a(?:nd?)?|in)\b
---
Fourscore  seven years ago our fathers brought forth
on  continent  new nation, conceived  liberty, 
dedicated   proposition  all men are created equal.

答案 1 :(得分:6)

我最好的解决方案:

$wholeText =~ s/$_//g for @stopWords;

您可能希望使用一些\b和空格来锐化正则表达式。

答案 2 :(得分:3)

怎么样:

my $qrstring = '\b(' . (join '|', @stopWords) . ')\b';
my $qr = qr/$qrstring/;
$wholeText =~ s/$qr/ /g;

连接所有单词以形成'\b(and|the|it|...)\b';连接周围的括号是必要的,以给它一个列表上下文;如果没有它们,你最终会计算出单词的数量)。 '\b'元字符标记单词边界,因此可以防止您将'千'变为'thous'。将其转换为带引号的正则表达式;将其全局应用于您的主题字符串(以便在单个操作中删除所有出现的所有停用词)。

您也可以不使用变量“$qr”:

my $qrstring = '\b(' . (join '|', @stopWords) . ')\b';
$wholeText =~ s/$qrstring/ /g;

我认为我不想维护那些没有变量“$qrstring”的人的代码;它可能已经完成,但我不认为它会非常易读。

答案 3 :(得分:3)

我的偏执狂版本:

$wholeText =~ s/\b\Q$_\E\b/ /gi for @stopWords;

使用\b匹配字边界,\Q..\E以防止任何停用词包含可能被正则表达式引擎解释为“特殊”的字符。

答案 4 :(得分:3)

您可以考虑使用正则表达式连接来创建单个正则表达式。

my $regex_str = join '|', map { quotemeta } @stopwords;
$string =~ /$regex_str/ /g;

请注意,quotemeta部分只是确保正确转义任何正则表达式字符。

答案 5 :(得分:-1)

grep{$wholeText =~ s/\b$_\b/ /g}@stopWords;