Skip to content

Instantly share code, notes, and snippets.

@ernado
Last active August 29, 2015 13:56
Show Gist options
  • Select an option

  • Save ernado/8870444 to your computer and use it in GitHub Desktop.

Select an option

Save ernado/8870444 to your computer and use it in GitHub Desktop.
# coding=utf-8
# python 2.7.6
# Alexander Razumov (ernado)
# с подсветкой кода: https://gist.github.com/ernado/8870444#file-check-py
"""
1. e-mail состоит из имени и доменной части, эти части разделяются символом "@";
2. доменная часть не короче 3 символов и не длиннее 256, является набором непустых строк, состоящих из символов a-z 0-9_- и разделенных точкой;
3. каждый компонент доменной части не может начинаться или заканчиваться символом "-";
4. имя (до @) не длиннее 128 символов, состоит из символов a-z0-9"._-;
5. в имени не допускаются две точки подряд;
6. если в имени есть двойные кавычки ", то они должны быть парными;
7. в имени могут встречаться символы "!,:", но только между парными двойными кавычками.
"""
import string
DOMAIN_DICT = string.ascii_letters.lower() + string.digits + '_-.'
NAME_DICT = DOMAIN_DICT + '"'
NAME_COMMA_DICT = NAME_DICT + '!,:'
def contains_bad_chars(s, dictionary):
"""
Checks that string contains only allowed chars
Returns True if string is valid, else returns False
:param s: input string
:param dictionary: allowed characters
:return: is invalid
"""
for char in s:
if char not in dictionary:
return True
return False
def check(s):
"""
Email validation. Returns True if email is valid, else - False
:type s: str
:param s: email
:return: email is valid
"""
assert isinstance(s, str)
email_parts = s.split('@')
if len(email_parts) != 2:
return False
# split email into username and domain
username, domain = email_parts
if len(domain) > 256 or len(domain) < 3:
return False
for domain_part in domain.split('.'):
if len(domain_part) == 0:
return False
# check first and last char != -
if domain_part[0] == '-' or domain_part[-1] == '-':
return False
if len(username) > 128 or not username:
return False
if username.find('..') != -1:
return False
quote_separated = username.split('"')
# check pairs for quotes
if (len(quote_separated) % 2) == 0:
return False
quote_first = 0
if username.find('"') == 0:
quote_first = 1
if contains_bad_chars(domain, DOMAIN_DICT):
return False
if contains_bad_chars(username, NAME_COMMA_DICT):
return False
for i, s in enumerate(quote_separated):
dictionary = NAME_COMMA_DICT
if i % 2 == quote_first:
# not quoted
dictionary = NAME_DICT
if contains_bad_chars(s, dictionary):
return False
return True
# coding=utf-8
# python 2.7.6
# Alexander Razumov (ernado)
# с подсветкой кода: https://gist.github.com/ernado/8870444#file-tests-py
import unittest
from check import check
class CheckTest(unittest.TestCase):
# e-mail состоит из имени и доменной части, эти части разделяются символом "@"
def test_check_at(self):
self.assertTrue(check('[email protected]'))
self.assertTrue(check('[email protected]'))
self.assertFalse(check('@noname.com'))
self.assertFalse(check('nothing'))
self.assertFalse(check('nodomen@'))
self.assertFalse(check('double@[email protected]'))
# доменная часть не короче 3 символов и не длиннее 256
def test_domain_length(self):
self.assertFalse(check('[email protected]'))
self.assertTrue(check('test@' + 's'*256))
self.assertFalse(check('test@' + 's'*257))
# является набором непустых строк, состоящих из символов a-z 0-9_- и разделенных точкой
def test_domain_chars(self):
self.assertTrue(check('test@abcde09-test_lan.dot.com.ru'))
self.assertFalse(check('test@abcde&.ru'))
self.assertFalse(check('[email protected]'))
self.assertFalse(check('test@test.ру'))
# каждый компонент доменной части не может начинаться или заканчиваться символом "-"
def test_domain_dash(self):
self.assertFalse(check('[email protected]'))
self.assertFalse(check('[email protected]'))
self.assertFalse(check('[email protected]'))
self.assertTrue(check('[email protected]'))
# имя не длиннее 128 символов
def test_username_length(self):
self.assertTrue(check('s'*128 + '@yandex.ru'))
self.assertFalse(check('s'*129 + '@yandex.ru'))
# имя состоит из символов a-z0-9"._-
def test_username_chars(self):
self.assertFalse(check('et#[email protected]'))
self.assertFalse(check('e%#[email protected]'))
self.assertFalse(check('e!,:[email protected]'))
self.assertTrue(check('"test.test-test_test"[email protected]'))
# в имени не допускаются две точки подряд;
def test_username_dots(self):
self.assertFalse(check('[email protected]'))
self.assertFalse(check('[email protected]'))
self.assertFalse(check('[email protected]'))
self.assertTrue(check('[email protected]'))
# если в имени есть двойные кавычки ", то они должны быть парными
def test_username_paired_quotes(self):
self.assertTrue(check('test"test"test"testtest"[email protected]'))
self.assertFalse(check('test"test"testtesttest"[email protected]'))
# в имени могут встречаться символы "!,:", но только между парными двойными кавычками.
def test_username_quoted(self):
self.assertTrue(check('test"te!,:st"[email protected]'))
self.assertFalse(check('testte!,:st"test"@ya.ru'))
self.assertFalse(check('tes"tte!",:[email protected]'))
if __name__ == '__main__':
unittest.main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment