【发布时间】:2013-03-21 15:19:20
【问题描述】:
给定一些任意文本,我想提取所有电子邮件地址和“邮箱说明符”(例如"Fred Smith" <fred@me.com>)。我查看了 NSDataDetector,但它不处理电子邮件地址。
【问题讨论】:
标签: ios objective-c macos nsdatadetector
给定一些任意文本,我想提取所有电子邮件地址和“邮箱说明符”(例如"Fred Smith" <fred@me.com>)。我查看了 NSDataDetector,但它不处理电子邮件地址。
【问题讨论】:
标签: ios objective-c macos nsdatadetector
解决这个问题的方法是获得一个非常好的算法,可以检测尽可能多的有效地址,并拒绝不正确的地址。最好的解决方案可能是使用 lex 和 yacc 构建的解析器,但使用正则表达式存在合理的解决方案。
请参阅此site 以获取经过测试的正则表达式列表以及对问题和可能解决方案的更深入讨论。
上述网站上显示的正则表达式针对 PHP 进行了格式化,并具有前导和尾随“/”标记,以及表示不区分大小写等的“标志”等(有关更多信息,请参阅此 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])];
但是,我们知道所有电子邮件地址都包含一个“@”,因此在处理字符串之前验证该字符串是否至少包含一个可能是值得的。此外,由于文本中可能包含换行符和/或回车符,您可能需要先删除它们。最好将它们完全剥离,因为某些邮件程序可能会在地址的某个内部点拆分一行。
一旦你有了地址范围的列表,那么大部分工作就完成了——如果你想要的只是地址的话。但是,地址通常以“邮箱说明符”格式显示,其中名称被添加到地址前,地址用“”包裹。这种格式在 RFC5322 的第 3.4 节中介绍。
要从“邮箱说明符”中恢复名称,请检查地址是否用“”包裹,如果是,则查找“
同样的技术可以用于实时验证——比如当文本字符串变成有效的电子邮件地址时启用提交按钮。在这种情况下,您评估每个用户更改的字符串,并启用/禁用提交按钮。
如果所有这些看起来都需要大量的编码工作,您可以在 github 上获取一个开源项目。
EDIT1:有关更快但不太严格的方法,请参阅 CodaFi 的评论。
EDIT2:看起来“mailto: URL 的内容可能相当复杂,github 项目只处理最简单的,并没有对地址进行反编码。这将在以后的更新中解决。
EDIT3:该项目已更新为完全处理“mailto:”对象,并返回到、cc、bcc、主题和正文,所有 URL 解码。
【讨论】: