Может ли оператор подстановки Perl соответствовать элементу в массиве? - PullRequest
8 голосов
/ 27 октября 2010

У меня есть такой массив

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

Мой текст находится в этой переменной

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

Я хочу сопоставить каждое вхождение каждого элемента моего массива stopWords в скалярном целом текстеи замените его пробелами.

Один из способов сделать это заключается в следующем:

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

Это работает и заменяет каждое вхождение всех стоп-слов.Мне просто интересно, есть ли более короткий способ сделать это.

Примерно так:

$wholeText =~ s/@stopWords/ /;

Хотя вышеприведенное, похоже, не работает.

Ответы [ 6 ]

7 голосов
/ 27 октября 2010

Хотя различные решения, основанные на map / for, будут работать , они также будут обрабатывать регулярные выражения вашей строки отдельно для каждого стоп-слова.Хотя в приведенном примере это не так уж и сложно, это может привести к серьезным проблемам с производительностью при увеличении целевого текста и списка стоп-слов.

Джонатан Леффлер и Роберт П. находятся на правильном пути, предлагая использовать все стоп-словавместе в одно регулярное выражение, но простой join из всех стоп-слов в одном чередовании является грубым подходом и, опять же, становится неэффективным, если список стоп-слов длинный.

Enter Regexp ::Соберите , который создаст вам более «умное» регулярное выражение для обработки всех совпадений - я использовал его с хорошим эффектом со списками из 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.
6 голосов
/ 27 октября 2010

Мое лучшее решение:

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

Возможно, вы захотите отточить регулярное выражение, используя \b и пробел.

3 голосов
/ 27 октября 2010

Вы можете использовать объединение регулярных выражений для создания одного регулярного выражения.

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

Обратите внимание, что часть quotemeta просто обеспечивает правильное экранирование любых символов регулярного выражения.

3 голосов
/ 27 октября 2010

Моя параноидальная версия:

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

Используйте \b для сопоставления границ слов и \Q..\E на всякий случай, если любое из ваших стоп-слов содержит символы, которые могут быть интерпретированы как "особые" механизмом регулярных выражений.

3 голосов
/ 27 октября 2010

Как насчет:

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

Объединить все слова в форму '\b(and|the|it|...)\b';круглые скобки вокруг объединения необходимы, чтобы дать ему контекст списка;без них вы в итоге подсчитаете количество слов).Метасимволы \b помечают границы слов и, следовательно, не позволяют вам заменить «тысяча» на «тыс.».Преобразуйте это в регулярное выражение в кавычках;примените его глобально к вашей строке темы (чтобы все вхождения всех стоп-слов были удалены за одну операцию).

Вы также можете обойтись без переменной '$qr':

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

Не думаю, что мне хотелось бы поддерживать код тех, кому удалось обойтись без переменной '$qrstring';это, вероятно, можно сделать, но я не думаю, что это было бы очень читабельным.

0 голосов
/ 27 октября 2010
grep{$wholeText =~ s/\b$_\b/ /g}@stopWords;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...