Необязательный токен для группы, кажется, предотвращает захват? - PullRequest
0 голосов
/ 19 декабря 2018

Я хочу записать текст в скобках X {} и Y {}:

echo "example ,X{whateverX},...,Y{whateverY} the end" | \
  perl -ne 'print "$2 $4 \n" if /.*(,X\{(.*?)\}).*(,Y\{(.*?)\})/;' 
whateverX whateverY

Теперь я хочу сделать присутствие X и / или Y необязательным, но как толькоЯ добавляю дополнительный модификатор, который останавливает сопоставление / захват:

echo "example ,X{whateverX},...,Y{whateverY} the end" | \
      perl -ne 'print "$2 $4 \n" if /.*(,X\{(.*?)\})?.*(,Y\{(.*?)\})?/;' 
<nothing printed>

ПРИМЕЧАНИЕ: выше я добавил?Модификатор в и каждой из групп X / Y, как выделено ниже (последний символ):

.\*(,X\\{(.\*?)\\})**?**

.\*(,Y\\{(.\*?)\\})**?**

Например, здесь у меня есть только Y как необязательный, и сопоставляется только X:

echo "example ,X{whateverX},...,Y{whateverY} the end" | \
      perl -ne 'print "$2 $4 \n" if /.*(,X\{(.*?)\}).*(,Y\{(.*?)\})?/;'
whateverX

Я ожидал, что все трое будут производить "whatX whatY", но только первый сделает ...

Чего мне не хватает?Почему необязательная группа захвата нарушает мое соответствие?

Ответы [ 3 ]

0 голосов
/ 20 декабря 2018

Специально, поскольку ваша вторая группа является необязательной, вы должны убедиться, что ваш средний сброс не соответствует. * В середине не совпадает с началом вашего второго блока:

echo "example ,X{whateverX},...,Y{whateverY} the end" | \
perl -ne 'print "$2 $4 \n" if /.*(,X\{(.*?)\})(?:(?!,Y).)*(,Y\{(.*?)\})?/;'
whateverX whateverY 

Важноебит там это:

(?:(?!,Y).)*

(?:) гарантирует, что это не группа захвата

(?!, Y) гарантирует, что этот блок не включаетстрока, Y

Если вы хотите быть более точным, вы также можете использовать (?!, Y {).

0 голосов
/ 20 декабря 2018

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

/X\{(?<X>.*?)\}|Y\{(?<Y>.*?)\}/g

regex 101 demo

0 голосов
/ 20 декабря 2018

Вам следует напомнить себе об основных аспектах регулярных выражений: по умолчанию они жадные, если может совпадать все выражение.

Ваш пример

/.*(,X\{(.*?)\})?.*(,Y\{(.*?)\})?/

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

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

Трудно сделать X {} и Y{} необязательно, но предпочитая их присутствие;Если вы сделаете их необязательными, механизм регулярных выражений никогда не будет использовать их, если с этим не справится.

Я бы предложил использовать подвыражения с чередующимися комбинациями X {} и Y {}, присутствующими либо внутри (?:...|...) (с последующим присвоением значений переменным в зависимости от используемой ветви) или внутри сброса ветви (?|...|...) (записывается как правильный код для использования /x):

use strict;
use warnings;

foreach my $data (<DATA>) {
    chomp $data;

    if ($data =~ /
                     (?|
                         .*?                  # both X and Y present
                         ,X \{ ([^{}]*) \}
                         .*?
                         ,Y \{ ([^{}]*) \}
                     |
                         .*?                  # only X present
                         ,X \{ ([^{}]*) \}
                         .*
                         ()
                     |
                         .*?                  # only Y present
                         ()
                         ,Y \{ ([^{}]*) \}
                     |                
                         () ()                # neither X nor Y present
                     )
                 /x) {

        print "$1, $2\n";
    }
}

exit 0;

__DATA__
example ,X{whateverX},...,Y{whateverY} the end
example2 ,X{whateverX2},random data to the end
example3 with data before ,Y{whateverY3} the end
example4 with just data and no separators

Будет выводить:

whateverX, whateverY
whateverX2, 
, whateverY3
, 

Обратите внимание, что необходимы ведущие .*?, иначе ()() будет совпадать в каждом случае.

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