Преобразуйте правила ABNF в REGEX
Мне нужно преобразовать упомянутые правила ABNF (mlaer) в REGEX
mlaer = 1*( lebal "." ) lebal
lebal = gid-tel *(rts-hdl)
rts-hdl = *( alpha / digit / "-" ) gid-tel
gid-tel = alpha / digit
alpha = %x41-5A ; 'A'-'Z'
alpha =/ %x61-7A ; 'a'-'z'
digit = %x30-39 ; '0'-'9'
Есть ли какой-либо инструмент или что-то, чтобы сделать это автоматически?
3 ответа
Следует помнить, что в общем смысле перевести ABNF в REGEX невозможно.
Это связано с тем, что регулярные выражения создают обычный язык , а спецификации ABNF создают контекстно-свободный язык .
Обычный язык может анализироваться с помощью конечного автомата (который также используется для сопоставления регулярных выражений), в то время как контекстно-свободный язык анализируется с помощью автомата с выталкиванием , который является надмножеством конечного автомата (автоматы с выталкиванием могут быть реализованы с помощью инструмент bison/yacc).
Примечание: сама строка регулярного выражения не может быть проверена с помощью выражения регулярного выражения. Это связано с тем, что разрешены скобки/круглые скобки, в то время как сопоставление скобок/круглых скобок не допускается с помощью регулярного выражения, а с помощью контекстно-свободной грамматики.
Следовательно, перевод из ABNF в регулярное выражение возможен только в некоторых случаях. Я предполагаю, что это тот случай, когда ABNF не рекурсивна или не содержит никаких циклических определений. Это (неявное) ограничение вышеупомянутых инструментов автоматического перевода.
Не уверен, есть ли какой-нибудь инструмент, чтобы сделать это автоматически, но это не слишком сложно.
gid-tel
[A-Za-z0-9]
rts-hdl
[A-Za-z0-9-]*[A-Za-z0-9]
lebal
[A-Za-z0-9]([A-Za-z0-9-]*[A-Za-z0-9])*
Обратите внимание, что lebal
написанное в этой форме заставит механизм NFA работать очень долго при вводе определенного типа. Это должно быть переписано как:
[A-Za-z0-9]([A-Za-z0-9-]*[A-Za-z0-9])?
mlaer
([A-Za-z0-9]([A-Za-z0-9-]*[A-Za-z0-9])?\.)+[A-Za-z0-9]([A-Za-z0-9-]*[A-Za-z0-9])?
Вы можете создать сложное регулярное выражение, используя конкатенацию строк. Это позволит вам писать чистый код. Хотя в случае с lebal
необходимо изменить грамматику, чтобы она хорошо работала на двигателе NFA.
Для небольших ABNF этот онлайн-инструмент, написанный на PHP, работал для меня. В вашем случае это возвращает:
gid-tel: ^([A-Z][a-z0-9])$
rts-hdl: ^(([A-Z][-a-z0-9])*([A-Z][a-z0-9]))$
lebal: ^([A-Z][a-z0-9])((([A-Z][-a-z0-9])*([A-Z][a-z0-9])))*$
mlaer: ^(([A-Z][a-z0-9])((([A-Z][-a-z0-9])*([A-Z][a-z0-9])))*\.)+([A-Z][a-z0-9])((([A-Z][-a-z0-9])*([A-Z][a-z0-9])))*$
Но для больших ABNF, таких как адрес электронной почты, выводится только пустым. В настоящее время я ищу другие инструменты и нашел странный маленький скрипт на Perl и один написанный на Ruby почти 17 лет назад, а последний - 7 лет назад. Последний выглядит многообещающе, так как на самом деле дает RegEx для URI ABNF, но мне все еще нужно заставить его работать.