# Вспомогательные переменные, позволяющие избавиться от лишних символов \. $esc = '\\\\'; $Period = '\.'; $space = '\040'; $tab = '\t'; $OpenBR = '\['; $CloseBR = '\]'; $OpenParen = '\('; $CloseParen = '\)'; $NonASCII = '\x80-\xff'; $ctrl = '\000-\037'; $Crlist = '\n\015'; # Примечание: должно быть \015. # Элементы 19, 20, 21 $qtext = qq/[^$esc$NonASCII$CRlist"]/; # внутри "..." $dtext = qq/[^$esc$NonASCII$CRlist$OpenBR$CloseBR]/; # внутри [...] $quoted_pair = qq< $esc [^$NonASCII] >; # экранированный символ # Элементы 22 и 23 - комментарий. # Реализовать общий случай при помощи регулярного выражения # невозможно. В данном примере допускается один уровень вложенности. $ctext = qq< [^$esc$NonASCII$CRlist()] >; # $Cnested совпадает с одним не-вложенным комментарием. # При раскрутке нормальным элементом считается $ctext, # а специальным - $quoted_pair. $Cnested = qq< $OpenParen # ( $ctext* # норм* (?: $quoted_pair $ctext* )* # (спец норм*)* $CloseParen # ) >; # $comment допускает один уровень вложенности для круглых скобок. # При раскрутке нормальным элементом считается $ctext, # а специальным - ($quoted_pair|$Cnested) $comment = qq< $OpenParen # ( $ctext* # норм* (?: # ( (?: $quoted_pair | $Cnested ) # спец $ctext* # норм* )* # )* $CloseParen # ) >; # $X - необязательные пропуски/комментарии. $X = qq< [$space$tab]* # Пропуски. (?: $comment [$space$tab]* )* # Если комментарий найден, возможны # присутствие дополнительных пропусков. >; # Элемент 10: atom $atom_char = qq/[^($space)<>\@,;:".$esc$OpenBR$CloseBR$ctrl$NonASCII]/; $atom = qq< $atom_char+ # Некоторое количество символов атома... (?!$atom_char) # ..за которыми не следует нечто, # не являющееся частью атома >; # Элемент 11: раскрученная строка в кавычках. $quoted_str = qq< " # " $qtext * # норм (?: $quoted_pair $qtext * )* # ( спец норм* )* " # " >; # Элемент 7: word - атом или строка в кавычках $word = qq< (?: $atom # Атом | # or $quoted_str # Строка в кавычках ) >; # Элемент 12: domain-ref - просто atom $domain_ref = $atom; # Элемент 13: domain-literal - аналог строки в кавычках, но вместо # "..." используется [...] $domain_lit = qq< $OpenBR # [ (?: $dtext | $quoted_pair )* # содержимое $CloseBR # ] >; # Элемент 9: sub-domain - domain-ref или domain-literal $sub_domain = qq< (?: $domain_ref | $domain_lit ) $X # optional trailing comments >; # Элемент 6: domain - список субдоменов (subdomain), разделенных точками. $domain = qq< $sub_domain (?: $Period $X $sub_domain )* >; # Элемент 8: route. Последовательность "@ $domain", разделенных запятыми, # и завершающаяся двоеточием. $route = qq< \@ $X $domain (?: , $X \@ $X $domain )* # Дополнительные домены : $X # Необязательные комментарии в конце >; # Элемент 6: local-part - последовательность $word, разделенных точками. $local_part = qq< $word $X (?: $Period $X $word $X # Дополнительные слова )* >; # Элемент 2: addr-spec - local@domain $addr_spec = qq< $local_part \@ $X $domain >; # Элемент 4: route-addr - $route_addr = qq[ < $X # < (?: $route )? # optional route $addr_spec # address spec > # > ]; # Элемент 3: phrase $phrase_ctrl = '\000-\010\012-\037'; # Аналог ctrl, но без табуляции # Аналог atom-char, но без пробела и с phrase_ctrl. # Поскольку класс является инвертированным, он совпадает с теми же # символами, что и atom-char, а также с пробелом и табуляцией $phrase_char = qq/[^()<>\@,;:".$esc$OpenBR$CloseBR$NonASCII$phrase_ctrl]/; # $word, $comment и $quoted_str не должны поглощать конечные экземпляры $X, # поскольку мы это делаем вручную. $phrase = qq< $word # Начальное слово $phrase_char * # "нормальные" атомы и/или пропуски (?: (?: $comment | $quoted_str ) # "специальный" комментарий # или строка в кавычках $phrase_char * # "нормальные" элементы )* >; ## Элемент 1: mailbox - addr_spec или phrase/route_addr $mailbox = qq< $X # Необязательный начальный комментарий (?: $addr_spec # address | # или $phrase $route_addr # Имя и адрес ) >;