我正在试图弄清楚如何从任何可能包含的引用回复文本中解析出电子邮件的文本.我已经注意到,通常电子邮件客户端会将"在某个日期等等上写下来"或者用尖括号作为前缀.不幸的是,不是每个人都这样做 有没有人知道如何以编程方式检测回复文本?我正在使用C#来编写这个解析器.
我做了很多搜索,这是我发现的.基本上有两种情况可以解决这个问题:当你有整个线程时,你什么时候没有.我将它分为两类:
当你有线程时:
如果您拥有整个系列的电子邮件,则可以非常高度地确保您要删除的内容实际上是引用的文本.有两种方法可以做到这一点.一,您可以使用消息的Message-ID,In-Reply-To ID和Thread-Index来确定单个消息,它的父节点以及它所属的线程.有关这方面的更多信息,请参阅RFC822,RFC2822,这篇关于线程的有趣文章,或有关线程的文章.一旦你重新组装了线程,你就可以删除外部文本(例如To,From,CC等......行),然后你就完成了.
如果您使用的邮件没有标题,您还可以使用相似性匹配来确定电子邮件的哪些部分是回复文本.在这种情况下,您仍然坚持进行相似性匹配以确定重复的文本.在这种情况下,您可能需要在代码项目或此项目中查看Levenshtein距离算法,例如此算法.
无论如何,如果您对线程处理过程感兴趣,请查看重新组装电子邮件线程的精彩PDF文件.
当你没有线程时:
如果您只遇到来自线程的一条消息,那么您必须尝试猜测引用的内容.在这种情况下,我看到的是不同的报价方法:
一条线(如展望中所示).
尖括号
" - -原始信息 - -"
"在某一天,某某写道:"
从那里删除文本,你就完成了.任何这些的缺点是,他们都假设发件人将他们的回复放在引用的文本之上并且没有交错它(就像互联网上的旧式一样).如果发生这种情况,祝你好运.我希望这可以帮助你们中的一些人!
首先,这是一项棘手的任务.
您应该从不同的电子邮件客户端收集典型的响应,并准备正确的正则表达式(或其他)来解析它们.我收集了来自outlook,thunderbird,gmail,apple mail和mail.ru的回复.
我正在使用正则表达式以下列方式解析响应:如果表达式不匹配,我尝试使用下一个.
new Regex("From:\\s*" + Regex.Escape(_mail), RegexOptions.IgnoreCase); new Regex("<" + Regex.Escape(_mail) + ">", RegexOptions.IgnoreCase); new Regex(Regex.Escape(_mail) + "\\s+wrote:", RegexOptions.IgnoreCase); new Regex("\\n.*On.*(\\r\\n)?wrote:\\r\\n", RegexOptions.IgnoreCase | RegexOptions.Multiline); new Regex("-+original\\s+message-+\\s*$", RegexOptions.IgnoreCase); new Regex("from:\\s*$", RegexOptions.IgnoreCase);
要删除报价到底:
new Regex("^>.*$", RegexOptions.IgnoreCase | RegexOptions.Multiline);
这是我的一小部分测试答案(样本除以---):
From: test@test.com [mailto:test@test.com] Sent: Tuesday, January 13, 2009 1:27 PM ---- 2008/12/26> text ---- test@test.com wrote: > text ---- test@test.com wrote: text text ---- 2009/1/13 > text ---- test@test.com wrote: text text ---- 2009/1/13 > text > text ---- 2009/1/13 > text > text ---- test@test.com wrote: > text > text ---- --- On Fri, 23/1/09, test@test.com wrote: > text > text
最诚挚的问候,Oleg Yaroshevych
感谢Goleg的正则表达!真的很有帮助.这不是C#,但对于那里的googlers,这是我的Ruby解析脚本:
def extract_reply(text, address) regex_arr = [ Regexp.new("From:\s*" + Regexp.escape(address), Regexp::IGNORECASE), Regexp.new("<" + Regexp.escape(address) + ">", Regexp::IGNORECASE), Regexp.new(Regexp.escape(address) + "\s+wrote:", Regexp::IGNORECASE), Regexp.new("^.*On.*(\n)?wrote:$", Regexp::IGNORECASE), Regexp.new("-+original\s+message-+\s*$", Regexp::IGNORECASE), Regexp.new("from:\s*$", Regexp::IGNORECASE) ] text_length = text.length #calculates the matching regex closest to top of page index = regex_arr.inject(text_length) do |min, regex| [(text.index(regex) || text_length), min].min end text[0, index].strip end
到目前为止它运作良好.
到目前为止,最简单的方法是在内容中放置一个标记,例如:
---请回答以上这一行---
毫无疑问,由于不同的电子邮件客户端以不同的方式引用文本,因此解析引用的文本并不是一项简单的任务.要正确解决此问题,您需要在每个电子邮件客户端中进行考虑和测试.
Facebook可以做到这一点,但除非你的项目有很大的预算,否则你可能不会.
奥列格用正则表达式解决了这个问题,找到了"2012年7月13日,13:09,xxx写道:"文字.但是,如果用户删除此文本,或者在电子邮件底部回复,就像许多人一样,此解决方案将无效.
同样,如果电子邮件客户端使用不同的日期字符串,或者不包含日期字符串,则正则表达式将失败.
电子邮件中没有回复的通用指示符.您可以做的最好的事情是尝试捕捉最常见的并解析新模式.
请记住,有些人在引用的文本中插入回复(例如我的老板在我问他们的同一行回答问题)所以不管你做什么,你可能会丢失一些你想要保留的信息.
这是@ hurshagrawal的Ruby代码的C#版本.我不太了解Ruby,所以它可能会关闭,但我认为我做对了.
public string ExtractReply(string text, string address) { var regexes = new List() { new Regex("From:\\s*" + Regex.Escape(address), RegexOptions.IgnoreCase), new Regex("<" + Regex.Escape(address) + ">", RegexOptions.IgnoreCase), new Regex(Regex.Escape(address) + "\\s+wrote:", RegexOptions.IgnoreCase), new Regex("\\n.*On.*(\\r\\n)?wrote:\\r\\n", RegexOptions.IgnoreCase | RegexOptions.Multiline), new Regex("-+original\\s+message-+\\s*$", RegexOptions.IgnoreCase), new Regex("from:\\s*$", RegexOptions.IgnoreCase), new Regex("^>.*$", RegexOptions.IgnoreCase | RegexOptions.Multiline) }; var index = text.Length; foreach(var regex in regexes){ var match = regex.Match(text); if(match.Success && match.Index < index) index = match.Index; } return text.Substring(0, index).Trim(); }