Как экспортировать регулярное выражение из модуля

#regex #perl

Вопрос:

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

 package regExport;
use strict;
use warnings;
use Exporter qw(import);
our @EXPORT_OK = qw(re);

my re = /.../; # my regex is here
 

и его привозят сюда

 use regExport qw(re);
my @li = ("man", "qwrt", "mnbv", "azx", "aeiou");

foreach my $st (@li) {
     $li =~ a/b/; # I wish to test my regex on each of these strings
}
 

У кого-нибудь есть какие-нибудь идеи, как бы я это сделал. Я чувствую себя довольно запутанным в том, как это сделать.

Комментарии:

1. Если вы хотите сделать переносимые экспортируемые регулярные выражения, взгляните на модуль Regexp::Common. metacpan.org/pod/Regexp::Common Таким образом, вам не придется возиться Exporter . Это также дает вам множество готовых регулярных выражений.

Ответ №1:

Самым простым, но не лучшим решением (см. Ниже) было бы создать переменную с шаблоном. Для этого лучше всего использовать qr — оператор, а затем экспортировать переменную

 package RegExport;

use strict;
use warnings;

use Exporter qw(import);
our @EXPORT_OK = qw($re_pattern);

our $re_pattern = qr/(w )/i;  # capture a "word" case-insensitive

1;
 

Обратите внимание, что я написал имя пакета с заглавной буквы в соответствии с обычным соглашением Perl для случая Pascal. (Тогда имя файла должно следовать за этим и быть RegExport.pm .)

Затем это используется в качестве

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

use FindBin qw($RealBin);
use lib $RealBin;

use RegExport qw($re_pattern);

my $text = q(Some text with a bunch of words. In sentences.);

while ($text =~ /$re_pattern/g) { 
    say "Word: $1";
}
 

Здесь я ожидаю RegExport.pm , что буду находиться в том же каталоге, что и программа. Использование $RealBin-хороший способ добавить в путь поиска включенных библиотек каталог относительно того, где находится сама программа (в данном случае, сам каталог программы).

Если вы действительно хотите использовать такую переменную (но читайте дальше!), то нет необходимости экспортировать ее из пакета, но вы можете использовать ее полное имя в вызывающем

 use RegExport;

... $RegExport::re_pattern ...
 

Это то, что иногда делается в библиотеках для различных настроек.

Тем не менее, в документации есть немного об этом, в разделе, что не следует экспортировать

Не экспортируйте имена переменных.

 @EXPORT_OK = qw($svar @avar %hvar); # DON'T!
 

Экспорт переменных — не очень хорошая идея. Они могут меняться под капотом, провоцируя ужасные эффекты на расстоянии, которые слишком трудно отследить и исправить. Поверьте мне: они того не стоят.

Этот хороший совет иногда нарушается в библиотеках, что дает хороший эффект; пример $RealBin приведен выше. Но если у вас нет для этого веских причин, то лучше следуйте этому-и используйте функцию для возврата значения

 package RegExport;

use strict;
use warnings;

use Exporter qw(import);
our @EXPORT_OK = qw(get_pattern);

sub get_pattern {
    my @specs = @_;  # any input on how to form the pattern

    my $re_pattern = qr{...};

    return $re_pattern;
}

1;
 

и теперь вы используете его как

 use RegExport qw(get_pattern);

my $re = get_pattern();   # or pass extra rules for how to form it
 

и используйте $re в регулярном выражении в качестве готового шаблона.

Теперь и пользователи этого кода, и будущие разработчики кода счастливы.

Комментарии:

1. @Jan : любая идея, что такое эквивалент Perl /regex/.test(string)

2. @MSS2001 Этот код проверяет в JS , соответствует ли регулярное string выражение, как логическое? В perl вы бы сделали my $bool = $string =~ /regex/; это $bool либо правдиво (обычно 1 ), либо ложно (обычно пустая строка). Часто ты бы просто так поступил if ($string =~ /regex/) ... . Это то, что использует моя примерная программа while (я отредактировал, чтобы добавить полный пример). Если вы назначаете в «контексте списка» ( my @matches = $string =~ /regex/; ), то вы получаете обратные совпадения, а не только true/false.

3. кроме того, это был чрезвычайно полезный bool и соответствует одному 🙂 спасибо (очень новичок в perl)

4. Экспортированные переменные можно сделать доступными только для чтения, чтобы устранить проблему. Проблема в том, как Exporter модуль выполняет импорт. Есть лучшие способы сделать это.

Ответ №2:

Вы были близки. С вашим кодом было всего несколько проблем:

  • Переменные, которые вы хотите экспортировать в другой пакет (т. Е. main ), должны быть объявлены как переменные пакета (с our ), а не лексические переменные (с my ).
  • Вы вызываете оператор соответствия ( / ... / ), а не объявляете и создаете регулярное выражение. qr/ ... / Вместо этого тебе нужно.
  • Несмотря на то , что вы загрузили Exporter , вам также необходимо сделать свой класс подклассом для использования import() .
  • В конце ваш пакет должен вернуть истинное значение.

Итак, у меня есть это в модуле:

 package RegExport;

use strict;
use warnings;

use Exporter;

our @ISA = qw(Exporter);
our @EXPORT = qw($re);

our $re = qr/[aeiou]/; # my regex is here
    
1;
 

И это в программе тестирования:

 use lib '.';
use feature 'say';

use RegExport;

my @li = ("man", "qwrt", "mnbv", "azx", "aeiou");
    
foreach my $st (@li) {
  if ($st =~ /$re/) {
    say "Match: $st";
  } else {
    say "No match: $st";
  }
}
 

Обратите внимание, что я изменил название вашей посылки на RegExport . В Perl существует традиция, что стандартные пользовательские модули начинаются с заглавной буквы.