На днях делал отсечение элементов списка не подходящих под регулярку введённую пользователем:
... my $re = get_text_in_filter(); @list = grep { /$re/i } @list; ...
$re был пустой строкой и в @list должны были остаться все элементы.

Так и происходило при первом проходе, а при втором регулярка не пропускала ни одного элемента списка.
Я предположил, что $re или @list изменились и распечатал их датапринтером:
use DDP; p my $x=[$re, qr/$re/, $list[0], $list[0] =~ qr/$re/? "ok":"no")]; # 1-й проход: [ [0] "", [1] (modifiers: u), [2] "Application", [3] "ok" ] # 2-й проход: [ [0] "", [1] (modifiers: u), [2] "Application", [3] "no" ]
С точки зрения датапринтера они не изменились. "В таком случае, возможно, в переменных какой-то флаг был установлен", продолжал рассуждать я. И сдампил $x дэвэл-пиком:
pop @$x; use Devel::Peek; Dump($x); # 1-й проход: SV = IV(0x56228695d7f8) at 0x56228695d808 REFCNT = 1 FLAGS = (ROK) RV = 0x56228708a930 SV = PVAV(0x56228712b618) at 0x56228708a930 REFCNT = 1 FLAGS = () ARRAY = 0x562287095590 FILL = 2 MAX = 3 FLAGS = (REAL) Elt No. 0 SV = PV(0x56228708c200) at 0x562286bfdbb0 REFCNT = 1 FLAGS = (POK,pPOK) PV = 0x562286fd9930 ""\0 CUR = 0 LEN = 10 Elt No. 1 SV = IV(0x5622870ac428) at 0x5622870ac438 REFCNT = 1 FLAGS = (ROK) RV = 0x562286c0ef68 SV = REGEXP(0x56228710d4a0) at 0x562286c0ef68 REFCNT = 1 FLAGS = (OBJECT,POK,FAKE,pPOK) PV = 0x5622870c04d0 "(?^u:)" CUR = 6 LEN = 0 STASH = 0x562285ffd230 "Regexp" COMPFLAGS = 0x100 () EXTFLAGS = 0x80000100 (NULL) ENGINE = 0x7f817615d380 (STANDARD) INTFLAGS = 0x0 () NPARENS = 0 LASTPAREN = 0 LASTCLOSEPAREN = 0 MINLEN = 0 MINLENRET = 0 GOFS = 0 PRE_PREFIX = 5 SUBLEN = 0 SUBOFFSET = 0 SUBCOFFSET = 0 SUBBEG = 0x0 MOTHER_RE = 0x562287123810 SV = REGEXP(0x56228710d3e0) at 0x562287123810 REFCNT = 2 FLAGS = (POK,pPOK) PV = 0x5622870c04d0 "(?^u:)" CUR = 6 LEN = 10 COMPFLAGS = 0x100 () EXTFLAGS = 0x80000100 (NULL) ENGINE = 0x7f817615d380 (STANDARD) INTFLAGS = 0x0 () NPARENS = 0 LASTPAREN = 0 LASTCLOSEPAREN = 0 MINLEN = 0 MINLENRET = 0 GOFS = 0 PRE_PREFIX = 5 SUBLEN = 0 SUBOFFSET = 0 SUBCOFFSET = 0 SUBBEG = 0x0 MOTHER_RE = 0x0 PAREN_NAMES = 0x0 SUBSTRS = 0x562287042a00 PPRIVATE = 0x562287130bb0 OFFS = 0x5622870153f0 QR_ANONCV = 0x0 SAVED_COPY = 0x0 PAREN_NAMES = 0x0 SUBSTRS = 0x562287042970 PPRIVATE = 0x562287130bb0 OFFS = 0x562287095090 QR_ANONCV = 0x0 SAVED_COPY = 0x0 Elt No. 2 SV = PVNV(0x5622870402a0) at 0x562286bfdd00 REFCNT = 1 FLAGS = (POK,IsCOW,pPOK) IV = 0 NV = 0 PV = 0x562287130eb0 "Application"\0 CUR = 11 LEN = 13 COW_REFCNT = 3 # 2-й проход: SV = IV(0x56228695d7f8) at 0x56228695d808 REFCNT = 1 FLAGS = (ROK) RV = 0x562287058898 SV = PVAV(0x562287139a90) at 0x562287058898 REFCNT = 1 FLAGS = () ARRAY = 0x5622871cb700 FILL = 2 MAX = 3 FLAGS = (REAL) Elt No. 0 SV = PV(0x56228713b690) at 0x56228712e378 REFCNT = 1 FLAGS = (POK,pPOK) PV = 0x562287113620 ""\0 CUR = 0 LEN = 10 Elt No. 1 SV = IV(0x5622871c7be0) at 0x5622871c7bf0 REFCNT = 1 FLAGS = (ROK) RV = 0x5622871419b8 SV = REGEXP(0x56228710d860) at 0x5622871419b8 REFCNT = 1 FLAGS = (OBJECT,POK,FAKE,pPOK) PV = 0x5622870c04d0 "(?^u:)" CUR = 6 LEN = 0 STASH = 0x562285ffd230 "Regexp" COMPFLAGS = 0x100 () EXTFLAGS = 0x80000100 (NULL) ENGINE = 0x7f817615d380 (STANDARD) INTFLAGS = 0x0 () NPARENS = 0 LASTPAREN = 0 LASTCLOSEPAREN = 0 MINLEN = 0 MINLENRET = 0 GOFS = 0 PRE_PREFIX = 5 SUBLEN = 0 SUBOFFSET = 0 SUBCOFFSET = 0 SUBBEG = 0x0 MOTHER_RE = 0x562287123810 SV = REGEXP(0x56228710d3e0) at 0x562287123810 REFCNT = 2 FLAGS = (POK,pPOK) PV = 0x5622870c04d0 "(?^u:)" CUR = 6 LEN = 10 COMPFLAGS = 0x100 () EXTFLAGS = 0x80000100 (NULL) ENGINE = 0x7f817615d380 (STANDARD) INTFLAGS = 0x0 () NPARENS = 0 LASTPAREN = 0 LASTCLOSEPAREN = 0 MINLEN = 0 MINLENRET = 0 GOFS = 0 PRE_PREFIX = 5 SUBLEN = 0 SUBOFFSET = 0 SUBCOFFSET = 0 SUBBEG = 0x0 MOTHER_RE = 0x0 PAREN_NAMES = 0x0 SUBSTRS = 0x562287042a00 PPRIVATE = 0x562287130bb0 OFFS = 0x5622870153f0 QR_ANONCV = 0x0 SAVED_COPY = 0x0 PAREN_NAMES = 0x0 SUBSTRS = 0x5622871b0af0 PPRIVATE = 0x562287130bb0 OFFS = 0x562287093f70 QR_ANONCV = 0x0 SAVED_COPY = 0x0 Elt No. 2 SV = PVNV(0x562287040580) at 0x5622871cdc18 REFCNT = 1 FLAGS = (POK,IsCOW,pPOK) IV = 0 NV = 0 PV = 0x562286fe39d0 "Application"\0 CUR = 11 LEN = 13 COW_REFCNT = 3
meld показал что различия только в указателях на память, флаги у значений оказались одинаковыми:

"В таком случае дело в какой-то внутренней переменной perl-а, которая влияет на поведение пустой регулярки", решил я.
Я уж думал поднять исходники perl-а, но для начала загуглил. Оказалось, что данное поведение регулярок описано в perlop. А именно у оператора матчинга (=~): оказывается, при использовании регулярка запоминается perl-ом, а пустая регулярка матчит как предыдущая. Что видно на следующем примере:
$x = "abc"; $y = "xby"; $x =~ /b/; print $`; # -> a $y =~ //; print $`; # -> x
Причём предыдущая регулярка может быть использована где угодно:
sub f1 { $_[0] =~ /b/; print $`; } sub f2 { f1(@_) } $x = "abc"; $y = "xby"; f2($x); # -> a $y =~ //; print $`; # -> x
То есть между двумя проходами отбора элементов списка где-то была использована регулярка, которая запомнилась и была использована пустой регуляркой. Проблема в том, что пустая это регулярка или нет perl определяет не на стадии компиляции. То есть он вначале интерполирует регулярку, а потом уже судит:
$x = "abc"; $y = "xby"; $x =~ /b/; print $`; # -> a my $re = ""; $y =~ /$re/; print $`; # -> x
Но если переменная $re не пустая:
$x = "abc"; $y = "xby"; $x =~ /b/; print $`; # -> a my $re = "y"; $y =~ /$re/; print $`; # -> xb
В perlop предлагается ставить () при использовании с переменной которая может быть пустой:
$x = "abc"; $_ = "xby"; $x =~ /b/; my $re = ""; $y =~ /()$re/; print $`; # -> print $'; # -> xby
Из особенностей пустой регулярки ещё нужно сказать о том, что она использует предыдущую регулярку не только в матчинге, но и при замене и не работает так в split (а просто бъёт строку на символы):
$x = "abc"; $_ = "xby"; $x =~ /b/; s//*/; print; # -> x*y $, = ", "; print split //, "abc"; # -> a, b, c
И ещё, что с эскейпингом /\Q$re\E/ она тоже считается пустой:
$x = "abc"; $y = "xby"; $x =~ /b/; print $`; # -> a my $re = ""; $y =~ /\Q$re\E/; print $`; # -> x
perl таит в себе множество тайн и когда уже думаешь, что знаешь о нём всё, оказывается, что ты лишь в начале долгого и увлекательного путешествия в мир кратких выражений.
Список использованной литературы
Пустой паттерн / https://perldoc.perl.org/perlop#The-empty-pattern-//
Проблема интерполяции паттерна / https://raku.org/archive/rfc/144.html
Повторяющиеся шаблоны поиска подстроки нулевой длины / https://metacpan.org/dist/POD2-RU/view/lib/POD2/RU/perlre.pod#Повторяющиеся-шаблоны-поиска-подстроки-нулевой-длины
