Создание подмножества с помощью регулярного выражения

#regex #perl

#регулярное выражение #perl

Вопрос:

У меня есть следующий список элементов измерения (неполный, на самом деле он намного длиннее):

 Ktr_12345_180
Ktr_12345_160
Ktr_12345_1130
Kst_12345_180
Kst_12345_112
Kst_12345_120
Kst_12345_160
  

Моя цель — создать подмножество элементов в редакторе подмножеств Jedox 2019.1.
Подмножество должно включать все элементы, начинающиеся с префикса "Ktr_" , но не имеющие суффикса _160 или _180

Я уже создал регулярное выражение (Ktr_) [0-9] (_180|_160) , которое идентифицирует элементы, которые мне не нужны.

Теперь я должен инвертировать его. Насколько мне известно, нет встроенной функции для инвертирования регулярного выражения, верно?

Итак, я попытался сделать это, используя отрицательный прогноз: (Ktr_) [0-9] (?!(_180|_160))

Это вообще не работает. Я пробовал это в разных формах, но не достиг своей цели…

Я ожидаю, что регулярное выражение доставит нужные элементы. Вместо этого он просто показывает каждый элемент, имеющий "Ktr_" в качестве префикса.

Ответ №1:

Проблема в том, что является жадным только настолько, насколько оно обеспечивает соответствие всему шаблону; в [0-9] нем совпадают не все следующие цифры, а только все такие, что остальные части шаблона также совпадают.

Захватите переменную часть шаблона ( [0-9] ) и распечатайте ее, чтобы увидеть

 my @ary = qw(
    Ktr_12345_180
    Ktr_12345_160
    Ktr_12345_1130  
    Kst_12345_180
);

for (@ary) { 
    say "got $1  in $_"  if /(Ktr_[0-9] )(?!_180|_160)/;
}
  

и мы получаем

получил Ktr_1234 в Ktr_12345_180 
получил Ktr_12345 в Ktr_12345_1130 
получил Ktr_1234 в Ktr_12345_160

Сопоставление 1234 оставляет 5 для удовлетворения ожидаемого значения «not _180» следующим после 1234 .

Чтобы настроить это, нам нужны подробные данные, и вопрос, похоже, допускает две возможности

  • Если всегда есть _ следующее, как следует из примеров данных, то просто включите _ перед началом просмотра

     /Ktr_[0-9] _(?!180|160)/
      

    что теперь требует, чтобы все цифры были сопоставлены раньше _ . Это также «обеспечивает соблюдение» _ там

  • Если мы будем следовать тому, что говорится в тексте

    все элементы, начинающиеся с префикса «Ktr_», но не имеющие суффикса _160 или _180

    тогда может не быть ничего следующего Ktr_12345 (например) или, по крайней мере, не _

    В этом случае необходимо принудительно сопоставлять только все последовательные цифры

     /Ktr_[0-9]  (?!_180|_160)/
      

    где дополнительный шаблон максимально соответствует своему предыдущему подшаблону, независимо от того, что следует дальше во всем шаблоне; он называется притяжательными кванторами

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

1. @ikegami Ах, но, конечно! Что-то меня беспокоит… Спасибо

Ответ №2:

Другой способ — сопоставить шаблон, а затем отрицать по сравнению с отрицательным внешним видом.

Попробуйте это

 $ cat paul.txt
Ktr_12345_180
Ktr_12345_160
Ktr_12345_1130
Kst_12345_180
Kst_12345_112
Kst_12345_120
Kst_12345_160
$ perl -lne ' print if /(Ktr_). ?(?<!_180|_160)b/ ' paul.txt
Ktr_12345_1130
$ perl -lne ' print if /(Ktr_) [0-9] . ?(?<!_180|_160)b/ ' paul.txt
Ktr_12345_1130
$
  

Ответ №3:

Правильное регулярное выражение, которое вам нужно, это,

 bKtr_[0-9] _(?!1[68]0b)[0-9] b
  

Здесь b границы слов вокруг регулярного выражения гарантируют, что оно не даст частичного совпадения в более крупном тексте, и (?!1[68]0b) это отрицательный прогноз, необходимый для отклонения строк, которые являются либо 160 , либо 180 , а остальная часть шаблона похожа на вашу. Кроме того, если вам не нужна группа, вам не нужно записывать первую часть как (Ktr_) и также это позволит Ktr_ использовать ее целиком один или несколько раз, что, глядя на ваши образцы, кажется, вам нежелательным. Итак, я изменил его на простое Ktr_ только, но в случае, если это было допустимым и действительно необходимым, сохраните его, заменив Krt_ на (Ktr_)

ДЕМОНСТРАЦИЯ

Ответ №4:

Вы можете использовать притяжательный квантификатор с дополнительным, чтобы гарантировать, что [0-9] совпадет столько цифр, сколько присутствует, и не пытаться выполнить обратный поиск, если совпадение не удается.

 (Ktr_) [0-9]  (?!(_180|_160))
  

Притяжательные кванторы доступны начиная с Perl 5.10 или раньше с синтаксисом pattern)» rel=»nofollow noreferrer»>независимого подвыражения.