Предварительная настройка начальной позиции поиска
Полезным свойством функции pos является то, что ей можно присваивать значение!
Например, вы знаете, что в переменной $s совпадение будет найдено только после тысячного символа. Вы можете начать поиск именно с этого символа, присвоив
pos($s)=1000;
Напомню, что счет символов идет с нуля. Но оператор поиска для использования этого значения должен иметь модификатор g (или gc). Вот пример:
$_='abcd'; pos($_)=1; /\w/g; print "$&\n"; pos($_)=1; print /\w/g;
На печати получим:
b bcd
Второй раз оператор поиска был использован в списковом контексте, потому что оператор print ожидает список значений.
Якорь \G учитывает значение, присвоенное функции pos, что видно на следующих примерах:
$_='abcd'; pos($_)=1; /\G\w/g; print "$&\n"; pos($_)=1; print /\G\w/g;
Результат такой же:
b bcd
А теперь рассмотрим более сложный пример, когда без якоря \G трудно организовать поиск. Предположим, данные представляют собой сплошную последовательность черырехзначных чисел без разделителей, и нам нужно отобрать из нее все числа, которые начинаются на 99.
Прямая попытка
my @a=/99\d\d/g
ведет к неудаче, потому что после несовпадения текущая позиция поиска будет увеличена на один символ и следующие итерации поиска не будут начинаться с начала чисел. В примере
$_='12991234'; my @a=/99\d\d/g; print @a;
будет "найдено" число 9912.
Попробуем вариант с минимальным квантификатором, который пропускает все четверки чисел до числа 99\d\d, а сохраняющие скобки захватывают в массив @a нужные числа:
$_='12991234'; my @a=/(?:\d{4})*?(99\d\d)/g; print @a;
Опять "найдено" число 9912… В этом примере при отсутствии совпадения (когда в тексте не останется нужных чисел) также применяется механизм смещения на один символ, и поиск продолжается не с границы чисел. Аналогично ведет себя негативная опережающая проверка с максимальным квантификатором:
$_='12991234'; my @a=/(?:(?!99)\d{4})*(99\d\d)/g; print @a;
Опять 9912… Первая пара скобок всегда заканчивается на границе числа, но при несовпадении второй пары будет смещение текущей позиции поиска, что все и портит.
Можно было бы ко второй паре скобок поставит квантификатор ?, чтобы при несовпадении со следующим числом эти захватывающие скобки совпали с пустым фрагментом, и это не привело бы к смещению текущей позиции поиска на один символ.
Но тогда в массиве @a появилось бы много элементов с неопределенным значением, потому что при каждой итерации поиска формировался бы очередной элемент массива независимо от того, найдено число или нет, - ведь теперь все регулярное выражение может совпасть с пустым фрагментом, а совпадение для захватывающих скобок вообще не обязательно.
Наиболее четкое и простое решение дает использование якоря \G. Он разрешает поиск только от конца предыдущего числа, не допуская увеличения текущей позиции поиска на один символ при несовпадении:
$_='12991234'; my @a=/\G(?:(?!99)\d{4})*(99\d\d)/g; print @a;
В этом примере поиск закончится неудачей и возвратится пустой список. В примере
$_='129912349934'; my @a=/\G(?:(?!99)\d{4})*(99\d\d)/g; print @a;
напечатается число 9934.