Включая регулярное выражение в переменной перед соответствием строки - PullRequest
0 голосов
/ 09 октября 2018

Я пытаюсь найти и извлечь слова, прочитанные из текстового файла в текстовом файле.До сих пор я могу найти только, когда слово написано правильно, а не ложно (изменено на @ или я изменил на 1).Можно ли добавить регулярное выражение в мои строки для сопоставления или что-то подобное?Пока это мой код:

sub getOccurrenceOfStringInFileCaseInsensitive
{
  my $fileName = $_[0];
  my $stringToCount = $_[1];
  my $numberOfOccurrences = 0;
  my @wordArray = wordsInFileToArray ($fileName);

  foreach (@wordArray)
  {
    my $numberOfNewOccurrences = () = (m/$stringToCount/gi);
    $numberOfOccurrences += $numberOfNewOccurrences;
  } 


  return $numberOfOccurrences;
}

Подпрограмма получает имя файла и строку для поиска.Подпрограмма wordsInFileToArray () просто получает каждое слово из файла и возвращает массив с ними.В идеале я хотел бы выполнить этот поиск непосредственно, читая из файла за один раз, вместо того, чтобы перемещать все в массив и повторять его.Но главный вопрос заключается в том, как жестко закодировать что-то в функцию, которая позволяет мне перехватывать ложные слова.

Пример: я хотел бы извлечь обе строки из файла.example.txt:

russ1 @ anh @ ck3r

russianhacker

# this variable also will be read from a blacklist file
$searchString = "russianhacker";
getOccurrenceOfStringInFileCaseInsensitive ("example.txt", $searchString);

Заранее благодарен за любые ответы.

Редактировать:

Возможные замены будут определены пользователем, и регулярное выражение должно быть установлено в соответствии.Пользователь может сказать, что обычной заменой является замена буквы «а» на «@» или даже «1».Возможное изменение совершенно произвольно.При поиске определенного слова (например, «русского») это можно сделать с помощью чего-то вроде:

(m/russian/i); # would just match the word as it is
(m/russi[a@1]n/i); # would match the munged word

Но я не уверен, как это сделать, если у меня есть строка для сопоставления, хранящаяся впеременная, такая как:

$stringToSearch = "russian";

Ответы [ 3 ]

0 голосов
/ 09 октября 2018

Есть части проблемы, которые не определены достаточно точно (пока).

Некоторые из подходов, которые зависят от деталей, сводятся к следующему:

  • Если определенные пользователем замены являются глобальными (заменять каждое вхождение символа в каждомстрока) пользователь может отправить сопоставление, как, скажем, хэш, и вы можете исправить их все.Процесс идентифицирует всех кандидатов на слова (наряду с фактическими, не исправленными словами, если они найдены).Могут быть ложные срабатывания, поэтому также планируйте некоторую постобработку

  • Если пользователь может предоставить список подстановок вместе с словами, к которым он применяется (искаженныеили соответствующие неполадки), тогда мы можем выполнить более целенаправленный прогон

Прежде чем это выяснится, есть еще один способ: использовать модуль для приблизительного («нечеткого») сопоставления.

String :: Approx , кажется, соответствует довольно многим из ваших требований.

Совпадение цели с заданной строкой основано на понятии расстояния редактирования Левенштейна : сколько вставок, удалений и замен («правок») требуется для получения заданнойСтрока в искомую цель.Максимальное допустимое количество правок может быть установлено.

Простой пример:

use warnings;
use strict;
use feature 'say';

use String::Approx qw(amatch);

my $target = qq(russianhacker);

my @text = qw(that h@cker was a russ1@anh@ck3r);

my @matches = amatch($target, ["25%"], @text);

say for @matches;     #==>  russ1@anh@ck3r

См. Документацию о том, что модуль нам помогает, но есть как минимум два комментария.

Во-первых, обратите внимание, что второй аргумент в amatch указывает допустимое отклонение в процентах от целевой строки.Для этого конкретного примера нам нужно разрешить редактировать каждый четвертый символ.Так много места для настройки может привести к случайным совпадениям, которые затем необходимо отфильтровать, поэтому потребуется некоторая постобработка.

Во-вторых, мы не поймали более легкого, h@cker.Модуль принимает фиксированный «шаблон» (цель), а не регулярное выражение, и может искать только один шаблон за раз.Итак, в принципе, вам нужен проход для каждой целевой строки.Это может быть улучшено, но будет больше работы.

Пожалуйста, изучите документацию;модуль предлагает намного больше, чем этот простой пример.

0 голосов
/ 10 октября 2018

Я решил проблему, включив регулярное выражение непосредственно в переменную, которую я буду использовать для сопоставления со строками моего файла.Это выглядит примерно так:

sub getOccurrenceOfMungedStringInFile
{
  my $fileName = $_[0];
  my $mungedWordToCount = $_[1];
  my $numberOfOccurrences = 0;

  open (my $inputFile, "<", $fileName) or die "Can't open file: $!";

  $mungedWordToCount =~ s/a/\[a\@4\]/gi;

  while (my $currentLine = <$inputFile>)
  {
    chomp ($currentLine);
    $numberOfOccurrences += () = ($currentLine =~ m/$mungedWordToCount/gi);
  }

  close ($inputFile) or die "Can't open file: $!";

  return $numberOfOccurrences;
}

Где строка:

$mungedWordToCount =~ s/a/\[a\@4\]/gi;

Это только одна из необходимых замен, а другие могут быть добавлены аналогичным образом.Я не знал, что Perl будет просто интерпретировать регулярное выражение внутри переменной, так как я пробовал это раньше, и мог получить желаемые результаты, определяя переменные внутри функции, используя одинарные кавычки.Должно быть, я сделал что-то не так в первый раз.

Спасибо за предложения, люди.

0 голосов
/ 09 октября 2018

Это своего рода проблема полнотекстового поиска, поэтому одним из способов является нормализация строк документа перед их сопоставлением.

use strict;
use warnings;
use Data::Munge 'list2re';
...
my %norms = (
  '@' => 'a',
  '1' => 'i',
  ...
);
my $re = list2re keys %norms;
s/($re)/$norms{$1}/ge for @wordArray;

Этот подход работает, только если существует только одна возможная "нормализованная форма"для любого заданного слова и может быть менее эффективным в любом случае, чем просто пробовать все возможные варианты строки поиска, если ваш документ достаточно велик, и вы пересчитываете его при каждом поиске.

Как примечание - ваше регулярное выражение m/$randomString/gi должно быть m/\Q$randomString/gi, так как вы не хотите, чтобы метасимволы регулярных выражений в $ randomString интерпретировались таким образом.См. Документы для quotemeta .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...