如何在文本中提取电子邮件/邮箱字符串列表或测试字符串是否是正确的电子邮件地址?

时间:2013-03-21 15:19:20

标签: ios objective-c macos nsdatadetector

鉴于一些任意文本,我想提取所有电子邮件地址和“邮箱说明符”(例如"Fred Smith" <fred@me.com>)。我查看了NSDataDetector,但它没有处理电子邮件地址。

1 个答案:

答案 0 :(得分:2)

解决这个问题的方法是获得一个非常好的算法,该算法可以检测尽可能多的有效地址,并拒绝不正确的地址。可能最好的解决方案是使用lex和yacc构造的解析器,但使用正则表达式存在合理的解决方案。

有关已测试正则表达式的列表以及对问题和可能解决方案的更深入讨论,请参阅此site

上面站点上显示的正则表达式是针对PHP格式化的,并且具有前导和尾随'/'标记,以及表示不区分大小写等的'flags'(有关详细信息,请参阅此site),所以在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])];

但是,我们知道所有电子邮件地址都包含一个“@”,因此在处理字符串之前验证字符串至少有一个可能是值得的。此外,由于文本中可能包含行和/或回车符,因此您可能希望先删除它们。完全剥离它们可能更好,因为某些邮件程序可能在地址的某个内部点分割了一行。

一旦你有一个地址范围列表,那么大部分工作就完成了 - 如果你想要的只是地址。但是,通常地址以“邮箱说明符”格式显示,其中名称前缀为地址,地址包含'&lt;'和'&gt;'。这种格式在RFC5322的3.4节中有所介绍。

要从'邮箱说明符'恢复名称,请检查地址是否包含'&lt;'和'&gt;',如果是这样,那么找到'&lt;'之前的字符串,忽略空格(直到找到第一个字符)。大多数名称将用双引号括起来(通常的做法),但实际上可以是使用反斜杠转义的裸字母数字字符串,以包含空格或其他特殊字符(如'“')。

这种技术可以用于实时验证 - 例如,当文本字符串成为有效的电子邮件地址时启用提交按钮。在这种情况下,您将评估每个用户更改时的字符串,并启用/禁用提交按钮。

如果所有这些代码都需要很多工作,那么您可以在github上获取一个开源项目。

EDIT1:对于更快但不太严谨的方法,请参阅CodaFi的评论。

EDIT2:看来“mailto:URL的内容可能非常复杂,github项目只处理最简单的,并且不会对地址进行解码。这将在以后的更新中解决。

EDIT3:项目已更新为完全处理“mailto:”对象,并返回,cc,bcc,subject和body,所有URL都已解码。