grep -P, чтобы найти строки, содержащие ровно n A, за которыми следует ровно n B

Можно ли написать команду grep -P (PCRE), которая печатает строки, содержащие только A и B, так что есть ровно n A, за которыми следует ровно n B, и никаких других символов . Так что это действительные совпадения:

AB
AAABBB
AAAAAAABBBBBBB
AAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBB

пока это не:

AAABB
ABBBBBB
BBBA
ABABA
BBBBBBBB

person Leon_wyl    schedule 24.02.2021    source источник
comment
Пожалуйста, перефразируйте как вопрос. Кроме того, у вас есть тег perl, но это вопрос grep.   -  person user3243135    schedule 24.02.2021
comment
Возможно, но вы пробовали что-нибудь?   -  person anubhava    schedule 24.02.2021
comment
Что вы пробовали? Какие у вас проблемы? Пожалуйста, покажите нам свой код.   -  person Dave Cross    schedule 24.02.2021
comment
Действительно, точная копия, связанная с @JamesBrown. С действительным ответом там. Проголосовали за закрытие   -  person zdim    schedule 27.02.2021


Ответы (1)


С обычными регулярными выражениями вы не можете этого сделать — они могут соответствовать только обычным контекстно-свободным языкам (введите 3 в Иерархия Хомского языков), в то время как то, что вы хотите сопоставить, является классическим примером языка типа 2.

К счастью, perl регулярные выражения не очень регулярны с точки зрения теории формального языка. Вы можете сопоставить это с помощью рекурсивного регулярного выражения:

$ perl -ne 'print if /^((?>A(?1)B|))$/' input.txt
AB
AAABBB
AAAAAAABBBBBBB
AAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBB
$ grep -P '^((?>A(?1)B|))$' input.txt  
AB
AAABBB
AAAAAAABBBBBBB
AAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBB

(Где input.txt содержит все ваши тестовые случаи).

Это соответствует либо пустой строке (0 символов A, за которыми следует 0 символов B), либо строке, начинающейся с A, успешному рекурсивному сопоставлению шаблона с остальной частью строки за вычетом первого и последнего символов и заканчивающейся буквой B. Если B появляется перед A, A после B, или общее количество A и B не совпадает, поэтому он терпит неудачу. (?>regex) – это оптимизация, предотвращающая откат после неудачного совпадения.

Если вы хотите применить n >= 1, небольшое изменение, чтобы поднять одну пару A и B за пределы рекурсивной секции: ^A((?>A(?1)B|))B$.

person Shawn    schedule 24.02.2021