Серьезно, прекратите. Это пустая трата времени и сил. Поищите регулярку для проверки Email в Google, взгляните на нее — и захочется отойти подышать свежим воздухом. Вспоминается одна очень известная цитата:
Некоторые люди, сталкиваясь с проблемой, думают: «О, я воспользуюсь регулярными выражениями».
Теперь у них две проблемы.Джэйми Завински, regex.info
Вот довольно часто встречающийся пример кода из приложения на Rails, содержащий некоторое подобие системы авторизации:
class User < ActiveRecord::Base
# Эта регулярка взята из проекта from https://github.com/plataformatec/devise,
# самой популярной библиотеки авторизации для Rails
validates_format_of :email, :with => /A[^@]+@([^@.]+.)+[^@.]+z/
end
Выглядит довольно просто (разве что если вы совсем не знаете регулярных выражений), но бывает и сильно хуже:
class User < ActiveRecord::Base
validates_format_of :email, :with => /^(|(([A-Za-z0-9]+_+)|([A-Za-z0-9]+-+)|([A-Za-z0-9]+.+)|([A-Za-z0-9]+++))*[A-Za-z0-9]+@((w+-+)|(w+.))*w{1,63}.[a-zA-Z]{2,6})$/i
end
Или совсем плохо:
class User < ActiveRecord::Base
validates :email, :with => EmailAddressValidator
end
class EmailValidator < ActiveModel::Validator
EMAIL_ADDRESS_QTEXT = Regexp.new '[^\x0d\x22\x5c\x80-\xff]', nil, 'n'
EMAIL_ADDRESS_DTEXT = Regexp.new '[^\x0d\x5b-\x5d\x80-\xff]', nil, 'n'
EMAIL_ADDRESS_ATOM = Regexp.new '[^\x00-\x20\x22\x28\x29\x2c\x2e\x3a-\x3c\x3e\x40\x5b-\x5d\x7f-\xff]+', nil, 'n'
EMAIL_ADDRESS_QUOTED_PAIR = Regexp.new '\x5c[\x00-\x7f]', nil, 'n'
EMAIL_ADDRESS_DOMAIN_LITERAL = Regexp.new "\x5b(?:#{EMAIL_ADDRESS_DTEXT}|#{EMAIL_ADDRESS_QUOTED_PAIR})*\x5d", nil, 'n'
EMAIL_ADDRESS_QUOTED_STRING = Regexp.new "\x22(?:#{EMAIL_ADDRESS_QTEXT}|#{EMAIL_ADDRESS_QUOTED_PAIR})*\x22", nil, 'n'
EMAIL_ADDRESS_DOMAIN_REF = EMAIL_ADDRESS_ATOM
EMAIL_ADDRESS_SUB_DOMAIN = "(?:#{EMAIL_ADDRESS_DOMAIN_REF}|#{EMAIL_ADDRESS_DOMAIN_LITERAL})"
EMAIL_ADDRESS_WORD = "(?:#{EMAIL_ADDRESS_ATOM}|#{EMAIL_ADDRESS_QUOTED_STRING})"
EMAIL_ADDRESS_DOMAIN = "#{EMAIL_ADDRESS_SUB_DOMAIN}(?:\x2e#{EMAIL_ADDRESS_SUB_DOMAIN})*"
EMAIL_ADDRESS_LOCAL_PART = "#{EMAIL_ADDRESS_WORD}(?:\x2e#{EMAIL_ADDRESS_WORD})*"
EMAIL_ADDRESS_SPEC = "#{EMAIL_ADDRESS_LOCAL_PART}\x40#{EMAIL_ADDRESS_DOMAIN}"
EMAIL_ADDRESS_PATTERN = Regexp.new "#{EMAIL_ADDRESS_SPEC}", nil, 'n'
EMAIL_ADDRESS_EXACT_PATTERN = Regexp.new "\A#{EMAIL_ADDRESS_SPEC}\z", nil, 'n'
def validate(record)
unless record.email =~ EMAIL_ADDRESS_EXACT_PATTERN
record.errors[:email] << 'is invalid'
end
end
end
Ага. Неужели действительно нужно использовать нечто настолько сложное? Если перейти по ссылке в начале статьи, вы увидите, что люди уже многие годы пишут (или пытаются написать) регулярки для проверки email-адреса, которые бы соответствовали описанию RFC. Некоторые из них оказываются просто до смешного заумными, как в последнем примере, и все равно не пропускают некоторые корректные адреса.
О том, какой email-адрес является корректным, написано в разделах 3.2.4 и 3.4.1. Там сказано, что при наличии обратного слэша и кавычек остается не так уж много вещей, которые нельзя использовать в адресе. Локальная часть адреса (та строка, что идет перед символом @), может содержать следующие символы:
! $ & * - = ^ ` | ~ # % ' + / ? _ { }
Но знаете что? Вы можете использовать практически любой символ, какой вам заблагорассудится, если заэкранируете его кавычками. Например, вот это — вполне корректный адрес:
"Look at all these spaces!"@ example.com
Прекрасно!
По этой причине, с недавнего времени я проверяю все email-адреса следующим регулярным выражением:
class User < ActiveRecord::Base
validates_format_of :email, :with => /@/
end
Элементарно, не правда ли? В адресе должен присутствовать символ @. Как правило, этим я и ограничиваюсь. Вкупе с полем для повторного ввода адреса два этих способа позволяют отсеять львиную долю ошибок, связанных со вводом некорректных данных.
Но что, если бы я предложил вам способ проверить email на валидность, в котором вообще не используются регулярные выражения? Он неожиданно прост, и, скорее всего, вы и так его применяете.
Просто пошлите пользователю его письмо!
Нет, я не шучу. Просто пошлите пользователю письмо. Практика посылки письма с кодом активации используется уже не один год, но практически всегда она дополняется сложной проверкой адреса. Если вы все равно собираетесь отправить на этот адрес письмо, зачем возиться с огромными регулярными выражениями?
Представьте себе такой сценарий. Я регистрируюсь на вашем сайте под следующим адресом:
qwiufaisjdbvaadsjghb@gmail.com
Да ладно вам! С этой хренью ни один почтовый демон работать не станет, но форматирование в полном порядке: это же валидный email-адрес! Для решения данной проблемы вы пишете систему, которая после регистрации отправляет мне email со ссылкой, по которой я должен перейти. Это требуется для того, чтобы удостовериться, что я действительно имею доступ к почтовому ящику, на который регистрируюсь. В таком случае, зачем проверять формат адресов? Результат отправки письма на неправильный адрес будет точно такой же — письмо не примет сервер. Если пользователь ввел некорректный адрес, он не получит письмо и попытается зарегистрироваться на вашем сайте еще раз, если ему это и правда нужно. Вот и все.
Так что не налегайте на замороченные регулярные выражения. Если вы правда хотите проверять адрес прямо на форме регистрации, добавьте поле для повторного ввода. Да, некоторые пользователи просто скопируют строку из первого и вставят во второе, но даже в этом случае незачем раздувать из этого проблему. Сложная валидация регулярными выражениями — это не дополнительное решение, а только лишний геморрой.
Если же вы все равно не можете успокоиться, пока не проверите адрес на корректность, просто проверьте на наличие в нем символа @. А если чувствуете, что способны на большее — добавьте проверку на точку:
/.+@.+..+/i
Все, что сверх этого — стрельба из пушки по воробьям.
Примечание переводчика:
Ссылку на эту статью нашел в комментарии к другому переводу. Спасибо jetman!
Автор: impwx