0

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

4

1 回答 1

2

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

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

上面网站上显示的正则表达式是为 PHP 格式化的,并且有前导和尾随的“/”标记,以及表示不区分大小写的“标志”等(有关更多信息,请参阅此网站),因此需要去掉这些在 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:”对象,并返回到、抄送、密件抄送、主题和正文,所有 URL 解码。

于 2013-03-21T15:19:20.280 回答