C# 从引用的回复解析电子邮件内容
我试图找出如何从任何引用的回复文本中解析出电子邮件的文本。我注意到,通常情况下,电子邮件客户会在“某某写的某某日期”或在行前加上尖括号。不幸的是,并不是每个人都这样做。有人知道如何以编程方式检测回复文本吗?我正在使用C#编写这个解析器。电子邮件中没有回复的通用指示符。您所能做的最好的事情就是尝试捕捉最常见的模式,并在遇到新模式时解析它们C# 从引用的回复解析电子邮件内容,c#,ruby,email,email-parsing,C#,Ruby,Email,Email Parsing,我试图找出如何从任何引用的回复文本中解析出电子邮件的文本。我注意到,通常情况下,电子邮件客户会在“某某写的某某日期”或在行前加上尖括号。不幸的是,并不是每个人都这样做。有人知道如何以编程方式检测回复文本吗?我正在使用C#编写这个解析器。电子邮件中没有回复的通用指示符。您所能做的最好的事情就是尝试捕捉最常见的模式,并在遇到新模式时解析它们 请记住,有些人会在引用的文本中插入回复(例如,我的老板会在我问他们的同一行上回答问题),因此无论你做什么,你都可能会丢失一些你想保留的信息。我对此做了大量搜索,
请记住,有些人会在引用的文本中插入回复(例如,我的老板会在我问他们的同一行上回答问题),因此无论你做什么,你都可能会丢失一些你想保留的信息。我对此做了大量搜索,以下是我的发现。基本上有两种情况下,你这样做:当你有整个线程时,当你没有。我将其分为两类: 当您有线程时: 如果你有整个系列的电子邮件,你可以达到一个非常高的保证水平,你删除的实际上是引用文本。有两种方法可以做到这一点。首先,您可以使用消息的消息ID、回复ID和线程索引来确定单个消息、它的父消息以及它所属的线程。有关此操作的详细信息,请参阅、或。一旦你重新组装了线程,你就可以删除外部文本(比如To,From,CC等…行),你就完成了 如果您正在处理的邮件没有标题,您还可以使用相似性匹配来确定电子邮件的哪些部分是回复文本。在这种情况下,您必须进行相似性匹配以确定重复的文本。在这种情况下,您可能需要研究一个诸如或之类的问题 不管怎样,如果您对线程过程感兴趣,请查看 当您没有线程时: 如果你只被一条来自该线程的消息所困扰,那么你必须试着猜测该引用是什么。在这种情况下,我看到的不同报价方法如下:
删除下面的文本,就完成了。这些方法的缺点是,它们都假设发送者将其回复放在引用文本的顶部,而不是交错(就像互联网上的旧样式一样)。如果真是这样,祝你好运。我希望这对你们中的一些人有所帮助 首先,这是一项棘手的任务 您应该从不同的电子邮件客户端收集典型的响应,并准备正确的正则表达式(或其他什么)来解析它们。我收集了来自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);
以下是我收集的一小部分测试响应(样本除以--):
来自:test@test.com[邮寄至:test@test.com]
发送日期:2009年1月13日星期二下午1:27
----
2008/12/26
>正文
----
test@test.com写的:
>正文
----
test@test.com写:文本
文本
----
2009/1/13
>正文
----
test@test.com写:文本
文本
----
2009/1/13
>正文
>正文
----
2009/1/13
>正文
>正文
----
test@test.com写的:
>正文
>正文
----
---2009年1月23日,星期五,test@test.com写的:
>正文
>正文
致以最诚挚的问候,Oleg Yaroshevych如果您控制原始消息(例如来自web应用程序的通知),您可以将一个独特的、可识别的头放在适当的位置,并将其用作原始帖子的分隔符。谢谢您,Goleg!真的很有帮助。这不是C#,但对于谷歌人来说,这是我的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
def extract_回复(文本、地址)
regex_arr=[
Regexp.new(“From:\s*”+Regexp.escape(address),Regexp::IGNORECASE),
Regexp.new(“,Regexp::IGNORECASE),
Regexp.new(Regexp.escape(地址)+“\s+写:”,Regexp::IGNORECASE),
Regexp.new(“^.*On.*(\n)?写:$”,Regexp::IGNORECASE),
Regexp.new(“-+原始\s+消息-+\s*$”,Regexp::IGNORECASE),
new(“from:\s*$”,Regexp::IGNORECASE)
]
text_length=text.length
#计算最接近页面顶部的匹配正则表达式
索引=正则表达式arr.inject(文本长度)do | min,正则表达式|
[(text.index(regex)| | text_长度),min].min
结束
文本[0,索引].strip
结束
到目前为止,它运行得非常好。到目前为止,最简单的方法是在内容中放置一个标记,例如: ---请在这一行以上回复--- 毫无疑问,您已经注意到,解析引用的文本并不是一项简单的任务,因为不同的电子邮件客户端以不同的方式引用文本。为了正确地解决这个问题,您需要在每个电子邮件客户端中进行帐户和测试 Facebook可以做到这一点,但除非你的项目预算很大,否则你可能无法做到 Oleg已经解决了使用正则表达式查找“文本”的问题。2012年7月13日13:09,xxx写道:“文本。但是,如果用户像许多人一样删除此文本或在电子邮件底部回复,此解决方案将无法工作 同样,如果电子邮件客户端使用不同的日期字符串,或者不包含日期字符串,正则表达式将失败。这是我的C版本的@hurshagrawal的Ruby代码。我不太了解Ruby,所以可能会关机,但我想我是对的
public string ExtractReply(string text, string address)
{
var regexes = new List<Regex>() { 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();
}
public string ExtractReply(字符串文本、字符串地址)
{
var regexes=new List(){new Regex(“From:\\s*”+Regex.Escape(address),RegexOptions.IgnoreCase),
新正则表达式(“,RegexOptions.IgnoreCase),
新正则表达式(正则表达式转义(地址)+“\\s+wrot
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
public string ExtractReply(string text, string address)
{
var regexes = new List<Regex>() { 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();
}
//Works for Gmail
new Regex("\\n.*On.*<(\\r\\n)?" + Regex.Escape(address) + "(\\r\\n)?>", RegexOptions.IgnoreCase),
//Works for Outlook 2010
new Regex("From:.*" + Regex.Escape(address), RegexOptions.IgnoreCase),