如何从电子邮件中删除引用的文本,仅显示新文本

我正在解析电子邮件。 当我看到对电子邮件的回复时,我想删除引用的文本,以便我可以将文本附加到上一封电子邮件中(即使是回复)。

通常情况下,您会看到:

第一封电子邮件(会话开始)

This is the first email 

第二封电子邮件(回复第一封)

 This is the second email Tim said: This is the first email 

这个输出只是“这是第二封电子邮件”。 虽然不同的电子邮件客户端以不同的方式引用文本,但如果只能获得大部分新的电子邮件文本,那么这也是可以接受的。

我使用以下正则表达式匹配引用文本的引导(最后一个是重要的):

  /** general spacers for time and date */ private static final String spacers = "[\\s,/\\.\\-]"; /** matches times */ private static final String timePattern = "(?:[0-2])?[0-9]:[0-5][0-9](?::[0-5][0-9])?(?:(?:\\s)?[AP]M)?"; /** matches day of the week */ private static final String dayPattern = "(?:(?:Mon(?:day)?)|(?:Tue(?:sday)?)|(?:Wed(?:nesday)?)|(?:Thu(?:rsday)?)|(?:Fri(?:day)?)|(?:Sat(?:urday)?)|(?:Sun(?:day)?))"; /** matches day of the month (number and st, nd, rd, th) */ private static final String dayOfMonthPattern = "[0-3]?[0-9]" + spacers + "*(?:(?:th)|(?:st)|(?:nd)|(?:rd))?"; /** matches months (numeric and text) */ private static final String monthPattern = "(?:(?:Jan(?:uary)?)|(?:Feb(?:uary)?)|(?:Mar(?:ch)?)|(?:Apr(?:il)?)|(?:May)|(?:Jun(?:e)?)|(?:Jul(?:y)?)" + "|(?:Aug(?:ust)?)|(?:Sep(?:tember)?)|(?:Oct(?:ober)?)|(?:Nov(?:ember)?)|(?:Dec(?:ember)?)|(?:[0-1]?[0-9]))"; /** matches years (only 1000's and 2000's, because we are matching emails) */ private static final String yearPattern = "(?:[1-2]?[0-9])[0-9][0-9]"; /** matches a full date */ private static final String datePattern = "(?:" + dayPattern + spacers + "+)?(?:(?:" + dayOfMonthPattern + spacers + "+" + monthPattern + ")|" + "(?:" + monthPattern + spacers + "+" + dayOfMonthPattern + "))" + spacers + "+" + yearPattern; /** matches a date and time combo (in either order) */ private static final String dateTimePattern = "(?:" + datePattern + "[\\s,]*(?:(?:at)|(?:@))?\\s*" + timePattern + ")|" + "(?:" + timePattern + "[\\s,]*(?:on)?\\s*"+ datePattern + ")"; /** matches a leading line such as * ----Original Message---- * or simply * ------------------------ */ private static final String leadInLine = "-+\\s*(?:Original(?:\\sMessage)?)?\\s*-+\n"; /** matches a header line indicating the date */ private static final String dateLine = "(?:(?:date)|(?:sent)|(?:time)):\\s*"+ dateTimePattern + ".*\n"; /** matches a subject or address line */ private static final String subjectOrAddressLine = "((?:from)|(?:subject)|(?:b?cc)|(?:to))|:.*\n"; /** matches gmail style quoted text beginning, ie * On Mon Jun 7, 2010 at 8:50 PM, Simon wrote: */ private static final String gmailQuotedTextBeginning = "(On\\s+" + dateTimePattern + ".*wrote:\n)"; /** matches the start of a quoted section of an email */ private static final Pattern QUOTED_TEXT_BEGINNING = Pattern.compile("(?i)(?:(?:" + leadInLine + ")?" + "(?:(?:" +subjectOrAddressLine + ")|(?:" + dateLine + ")){2,6})|(?:" + gmailQuotedTextBeginning + ")" ); 

我知道在某些方面这是过度的(可能会很慢!)但它的效果非常好。 如果您发现任何与此不符的内容,请告诉我,以便我可以改进!

查看Google专利: http : //www.google.com/patents/US7222299

总之,它们对文本的部分进行哈希处理(可能类似于句子),然后在先前的消息中查找与哈希的匹配。 速度非常快,他们也可能将此作为线程算法的输入。 真是个好主意!

当以前的电子邮件存储在磁盘上或可用的somwhow时,您可以检查所有邮件,由特定接收方发送以确定哪个是响应文本。

您还可以通过检查最后一行的第一个字符来尝试确定引号字符。 Normaly最后一行始终以相同的字符开头。

当最后两行以不同的字符开头时,您可以尝试第一行,因为有时答案会附加在文本的末尾。

如果您检测到这些字符,则可以删除以该字符开头的最后一行,直到检测到空行或以其他字符开头的行。

没有测试 ,更像是伪代码

  String[] lines; // Check the size of the array first, length > 2 char startingChar = lines[lines.length - 1].charAt(0); int foundCounter = 0; for (int i = lines.length - 2; i >=0; --i) { String line = lines[i]; // Check line size > 0 if(startingChar == line.charAt(0)){ ++foundCounter; } } final int YOUR_DECISION = 2; // You can decide if(foundCounter > YOUR_DECISION){ deleteLastLinesHere(startingChar, foundCounter); } 

RegEx工作正常,除了匹配从Subject开始的文本并忽略“Subject”之前的所有内容

 Text -------- Original Message -------- 
// the matcher starts working from here

通过观察Gmail在这方面的行为,我观察了他们的策略:

  1. 写完整的第二封邮件。
  2. 附加文字如:On [timestamp],[first email sender name] <[first email sender email address>>写道:
  3. 附上完整的第一封电子邮件。 一个。 如果您的电子邮件是纯文本,则在第一封电子邮件的每一行之前添加“>”。 湾 如果是HTML格式,那么Gmail会给出左侧边距:

    border-left:1px solid #CCC; 保证金:0px 0px 0px 0.8ex; padding-left:1ex; 用户代理样式表blockquote

    然后附加第一封电子邮件的文本。

您可以在解析来自Gmail地址的电子邮件时对此进行反向工程。 我没有调查其他客户,但他们应该有相同的行为。

你会用几行代码得到它几乎是正确的:

 String newMessage = ""; for (String line : emailLines) { if (!line.matches("^[>].*")) { newMessage = newMessage.concat(line); } } 

如有必要,您可以为电子邮件客户端添加其他正则表达式检查,这些客户端会留下不同的带引号的文本签名。