Как с помощью Perl показать контекст поискового запроса в результатах поиска?
-
03-07-2019 - |
Вопрос
Я пишу сценарий Perl, который ищет термин в больших частях текста.Я хотел бы отобразить пользователю небольшую часть текста вокруг поискового запроса, чтобы пользователь мог иметь представление о том, где используется этот поисковый запрос.Результаты поиска Google — хороший пример того, чего я пытаюсь достичь: контекст вашего поискового запроса отображается под заголовком ссылки.
Мой основной поиск использует это:
if ($text =~ /$search/i ) {
print "${title}:${text}\n";
}
($ title содержит название элемента, в котором был найден термин поиска). Это слишком много, поскольку иногда $ Text будет иметь сотни строк текста.
Это будет отображаться в Интернете, поэтому я мог бы просто предоставить заголовок как ссылку на фактический текст, но для пользователя нет контекста.
Я попытался изменить свое регулярное выражение, чтобы захватить 4 слова до и 4 слова после искомого условия, но столкнулся с проблемами, если поисковый запрос находился в самом начале или в самом конце $text.
Каким будет хороший способ добиться этого?Я попробовал выполнить поиск по CPAN, потому что уверен, что у кого-то есть модуль для этого, но не могу придумать, какие термины нужно искать.Я бы нравиться по возможности делать это без модулей, потому что устанавливать модули здесь - это боль.У кого-нибудь есть идеи?
Решение
Ваша первоначальная попытка написать 4 слова до/после была не так уж далека.
Пытаться:
if ($text =~ /((\S+\s+){0,4})($search)((\s+\S+){0,4})/i) {
my ($pre, $match, $post) = ($1, $3, $4);
...
}
Другие советы
Вы можете использовать $ и $ ', чтобы получить строку до и после совпадения. Затем соответствующим образом обрежьте эти значения. Но, как указывает blixtor, shlomif правильно предложить использовать
@ + и
@ - , чтобы избежать снижения производительности, налагаемого $
и # '-
$foo =~ /(match)/;
my $match = $1;
#my $before = Вы можете использовать $ и $ ', чтобы получить строку до и после совпадения. Затем соответствующим образом обрежьте эти значения. Но, как указывает blixtor, shlomif правильно предложить использовать
@ + и
@ - , чтобы избежать снижения производительности, налагаемого $
и # '-
;
#my $after = ;
my $before = substr($foo, 0, $-[0]);
my $after = substr($foo, <*>[0]);
$after =~ s/((?:(?:\w+)(?:\W+)){4}).*/$1/;
$before = reverse $before; # reverse the string to limit backtracking.
$before =~ s/((?:(?:\W+)(?:\w+)){4}).*/$1/;
$before = reverse $before;
print "$before -> $match <- $after\n";
Я бы предложил использовать позиционные параметры - @ + и @ - (см. perldoc perlvar), чтобы найти позицию в строке совпадения и узнать, сколько это займет.
Вы можете попробовать следующее:
if ($text =~ /(.*)$search(.*)/i ) {
my @before_words = split ' ', $1;
my @after_words = split ' ',$2;
my $before_str = get_last_x_words_from_array(@before_words);
my $after_str = get_first_x_words_from_array(@after_words);
print $before_str . ' ' . $search . ' ' . $after_str;
}
Некоторый код явно опущен, но это должно дать вам представление о подходе.
Что касается извлечения заголовка ... Я думаю, что этот подход не слишком хорош для этого.