Как извлечь список строк электронной почты / почтового ящика в тексте или проверить, является ли строка правильным адресом электронной почты?

Учитывая некоторый произвольный текст, я хотел бы извлечь все адреса электронной почты и "спецификаторы почтовых ящиков" (например, "Fred Smith" <fred@me.com>). Я посмотрел на NSDataDetector, но он не обрабатывает адреса электронной почты.

1 ответ

Чтобы достичь этого, нужно получить действительно хороший алгоритм, который может обнаружить как можно больше действительных адресов и отклонить неправильные. Вероятно, лучшим решением будет синтаксический анализатор, построенный с использованием lex и yacc, но разумные решения существуют с использованием регулярных выражений.

На этом сайте вы найдете список проверенных регулярных выражений, а также более глубокое обсуждение проблемы и возможных решений.

Регулярные выражения, показанные на вышеуказанном сайте, отформатированы для PHP и имеют начальные и конечные маркеры '/', а также 'flags', указывающие на регистр символов и т. Д. (См. Этот сайт для получения дополнительной информации), поэтому их необходимо удалить. перед использованием выражения в проекте Objective-C. Кроме того, любые якоря тоже нуждаются в удалении, поскольку нам нужно несколько адресов, а не только один (т. Е. '^' И '$').

NSRegularExpression - класс для использования здесь. Что мне показалось полезным - это сохранить регулярное выражение в файле в моем проекте, чтобы вам не приходилось беспокоиться о экранировании от обратной косой черты и кавычек. Затем код считывает выражение в строку и создает объект следующим образом:

NSString *fullPath = [[NSBundle mainBundle] pathForResource:self.regex ofType:@"txt"];
NSString *pattern = [NSString stringWithContentsOfFile:fullPath encoding:NSUTF8StringEncoding error:NULL];
__autoreleasing NSError *error = nil;
reg = [NSRegularExpression regularExpressionWithPattern:pattern options:NSRegularExpressionCaseInsensitive error:&error]; // some patterns may not need NSRegularExpressionCaseInsensitive
assert(reg && !error);

Получив инициализированное выражение, вы используете его для возврата списка диапазонов, каждый из которых является адресом:

NSArray *ret = [reg matchesInString:str options:0 range:NSMakeRange(0, [str length])];

Тем не менее, мы знаем, что все адреса электронной почты содержат один '@', поэтому, вероятно, стоит проверить, что в строке есть хотя бы один, прежде чем обрабатывать ее. Кроме того, поскольку в тексте могут быть строки и / или символы возврата каретки, вы можете сначала удалить их. Вероятно, лучше удалить их полностью, так как некоторые почтовые программы могли разделить строку в некоторой внутренней точке адреса.

Если у вас есть список диапазонов адресов, то по большей части работа выполняется - если вам нужен только адрес. Однако часто адреса представляются в формате "спецификатора почтового ящика", где к имени добавляется имя перед адресом и адрес, заключенный в символы "<" и ">". Этот формат описан в RFC5322, в разделе 3.4.

Чтобы восстановить имя из "спецификатора почтового ящика", проверьте, не обернут ли адрес "<" и ">", и, если это так, найдите строку, предшествующую "<", игнорируя пробел (пока не найдете первый персонаж). Большинство имен будут заключены в двойные кавычки (общепринятая практика), но на самом деле это могут быть открытые буквенно-цифровые строки, использующие обратную косую черту для включения пробела или других специальных символов (например, "").

Этот же метод можно использовать для проверки в реальном времени, например, для включения кнопки отправки, когда текстовая строка становится действительным адресом электронной почты. В этом случае вы оцениваете строку при каждом изменении пользователя и включаете / отключаете кнопку отправки.

Если все это кажется большой работой над кодом, вы можете получить проект с открытым исходным кодом на github.

EDIT1: для более быстрого, но менее строгого метода см. Комментарий CodaFi.

EDIT2: кажется, что содержимое "mailto: URL" может быть довольно сложным, проект github обрабатывает только самые простые и не расшифровывает адрес. Это будет решено в будущем обновлении.

EDIT3: проект был обновлен, чтобы полностью обрабатывать объекты "mailto:" и возвращать, cc, bcc, subject и body, все URL-кодировано.

Другие вопросы по тегам