銀月の符号

Python 使い見習いの日記・雑記

メールアドレスの正規表現

Perlメモ メールアドレスの正規表現 にある長大な正規表現 $mail_regex 。初めて見たのはたぶん 4 年前だと思う。そのときの衝撃はそれは大きなもので。メールアドレスにマッチする正規表現の作成は非常に難しいということを知った。この後 RFC 2822 とかも見たけど、この文章、正しく理解できる気がしない。

そんな複雑怪奇な正規表現を今日は再び眺めていた。唐突に Python への移植をしたくなった。そうして、できあがったのが以下のコード。時間をかけていないので、過ちがある可能性が大きいが、眠いのでテストは明日に。

import re

_r = {}
_r['esc'] = u'\\\\'
_r['Period'] = u'\\.'
_r['space'] = u'\x20'
_r['OpenBR'] = u'\\['
_r['CloseBR'] = u'\\]'
_r['NonASCII'] = u'\x80-\uffff' # UCS-2
#_r['NonASCII'] = u'\x80-\U0010ffff' # UCS-4
_r['ctrl'] = u'\x00-\x1f'
_r['CRlist'] = u'\x0a\x0d'
_r['qtext'] = u'[^%(esc)s%(NonASCII)s%(CRlist)s"]' % _r
_r['dtext'] = u'[^%(esc)s%(NonASCII)s%(CRlist)s%(OpenBR)s%(CloseBR)s]' % _r
_r['quoted_pair'] = u'%(esc)s[^%(NonASCII)s]' % _r
_r['atom_char'] = u'[^%(space)s<>@,;:".%(esc)s%(OpenBR)s%(CloseBR)s%(ctrl)s%(NonASCII)s]' % _r
_r['atom'] = u'%(atom_char)s+(?!%(atom_char)s)' % _r
_r['quoted_str'] = u'"%(qtext)s*(?:%(quoted_pair)s%(qtext)s*)*"' % _r
_r['word'] = '(?:%(atom)s|%(quoted_str)s)' % _r
_r['domain_ref'] = _r['atom']
_r['domain_lit'] = u'%(OpenBR)s(?:%(dtext)s|%(quoted_pair)s)*%(CloseBR)s' % _r
_r['sub_domain'] = u'(?:%(domain_ref)s|%(domain_lit)s)' % _r
_r['domain'] = u'%(sub_domain)s(?:%(Period)s%(sub_domain)s)*' % _r
_r['local_part'] = u'%(word)s(?:%(Period)s%(word)s)*' % _r
_r['addr_spec'] = u'%(local_part)s@%(domain)s' % _r

mail_regex = re.compile(_r['addr_spec'])
del _r

repr(mail_regex.pattern) により得られた文字列は次のもの。やはり人が読むものではない。

u'(?:[^ <>@,;:".\\\\\\[\\]\x00-\x1f\x80-\uffff]+(?![^ <>@,;:".\\\\\\[\\]\x00-\x1f\x80-\uffff])|"[^\\\\\x80-\uffff\n\r"]*(?:\\\\[^\x80-\uffff][^\\\\\x80-\uffff\n\r"]*)*")(?:\\.(?:[^ <>@,;:".\\\\\\[\\]\x00-\x1f\x80-\uffff]+(?![^ <>@,;:".\\\\\\[\\]\x00-\x1f\x80-\uffff])|"[^\\\\\x80-\uffff\n\r"]*(?:\\\\[^\x80-\uffff][^\\\\\x80-\uffff\n\r"]*)*"))*@(?:[^ <>@,;:".\\\\\\[\\]\x00-\x1f\x80-\uffff]+(?![^ <>@,;:".\\\\\\[\\]\x00-\x1f\x80-\uffff])|\\[(?:[^\\\\\x80-\uffff\n\r\\[\\]]|\\\\[^\x80-\uffff])*\\])(?:\\.(?:[^ <>@,;:".\\\\\\[\\]\x00-\x1f\x80-\uffff]+(?![^ <>@,;:".\\\\\\[\\]\x00-\x1f\x80-\uffff])|\\[(?:[^\\\\\x80-\uffff\n\r\\[\\]]|\\\\[^\x80-\uffff])*\\]))*'