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

у меня есть небольшой скрипт, который сопоставляется через регулярное выражение, если строка содержит немецкие умляуты, такие как äöüß. В первом совпадении регулярного выражения все работает нормально, но если я снова проверю ту же строку, она больше не соответствует правильно. Сам файл закодирован как utf8, и я также включаю модуль utf8.

это скрипт:

#!/usr/bin/perl
use strict;
use warnings FATAL => 'all';
use utf8;
use Log4Perl::logger_helper qw( init_logger get_logger_and_trace );

my $strings = ["ä", "ae","ö", "oe", "ü", "ue", "ß", "ss"];

my $logger = init_logger(
    log_file_path => $0 . '.log'
);    # init_logger variables are all optional

foreach my $string (@$strings) {
    for(1..5) {
        if ( $string =~ /[\x{00C4}\x{00E4}\x{00D6}\x{00F6}\x{00DC}\x{00FC}\x{00DF}]/gi ) {
            $logger->info("umlauts match $string");
        }
        else {
            $logger->info("no umlauts $string");
        }
    }
 }

и это вывод:

umlauts match ä
no umlauts ä
umlauts match ä
no umlauts ä
umlauts match ä
no umlauts ae
no umlauts ae
no umlauts ae
no umlauts ae
no umlauts ae
umlauts match ö
no umlauts ö
umlauts match ö
no umlauts ö
umlauts match ö
no umlauts oe
no umlauts oe
no umlauts oe
no umlauts oe
no umlauts oe
umlauts match ü
no umlauts ü
umlauts match ü
no umlauts ü
umlauts match ü
no umlauts ue
no umlauts ue
no umlauts ue
no umlauts ue
no umlauts ue
umlauts match ß
no umlauts ß
umlauts match ß
no umlauts ß
umlauts match ß
no umlauts ss
no umlauts ss
no umlauts ss
no umlauts ss
no umlauts ss

Process finished with exit code 0

Я тестировал его на разных ОС с разными версиями клубничного perl, также последняя версия (strawberry-perl-5.30.0.1-64bit-portable) показывает мне эту ошибку.

Любая идея, почему он правильно соответствует изменению? Если я делаю то же самое с несколькими операциями с индексами, это работает.

Заранее спасибо.


person wreggyl    schedule 28.11.2019    source источник


Ответы (2)


Проблема в флаге global. Убери это.

person daxim    schedule 28.11.2019
comment
привет, спасибо, это работает. У вас есть объяснение такому поведению? похоже, что указатель совпадения сохранен? - person wreggyl; 28.11.2019

Как объяснил @daxim, глобальный флаг /g вызывает здесь хаос.

Из операторов регулярных выражений, подобных кавычкам, важный раздел выделен в < сильный>жирный:

В скалярном контексте каждое выполнение m//g находит следующее совпадение, возвращая true, если оно совпадает, и false, если больше совпадений нет. Позицию после последнего совпадения можно прочитать или установить с помощью функции pos(). Неудачное совпадение обычно сбрасывает позицию поиска в начало строки, но этого можно избежать, добавив модификатор /c (например, m//gc). Изменение целевой строки также сбрасывает позицию поиска.

Поскольку вы повторно выполняете поиск в одном и том же $string (без его изменения между ними), каждый второй поиск продолжается после последнего успешного совпадения, что приводит к сбою и сбросу позиции поиска для следующего поиска.

См. также «Глобальное сопоставление» в разделе Использование регулярных выражений в Perl:

Модификатор /g обозначает глобальное сопоставление и позволяет оператору сопоставления выполнять сопоставление в строке столько раз, сколько возможно. В скалярном контексте последовательные вызовы строки будут иметь /g переход от совпадения к совпадению, отслеживая позицию в строке по мере ее продвижения. Вы можете получить или установить позицию с помощью функции pos().

Чао, Даниэль :-)

person D. Bachran    schedule 28.11.2019