Как удалить цитированный текст из электронной почты и показать только новый текст

Я разобрал электронные письма. Когда я вижу ответ на сообщение электронной почты, я хотел бы удалить цитированный текст, чтобы добавить текст в предыдущее письмо (даже если это ответ).

Как правило, вы увидите следующее:

1-й адрес электронной почты (начало разговора)

This is the first email

2-е письмо (сначала ответ)

This is the second email

Tim said:
This is the first email

Результатом этого будет "Только второе письмо". Хотя разные почтовые клиенты цитируют текст по-разному, если бы кто-то мог получить в основном только новый текст электронной почты, это также было бы приемлемым.

Ответ 1

Я использую следующие регулярные выражения для совпадения вывода для цитируемого текста (последний из них считается):

  /** 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 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, i.e.
   * 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 + ")"
                                                                      );

Я знаю, что в некотором роде это слишком много (и может быть медленным!), но это работает очень хорошо. Пожалуйста, дайте мне знать, если вы найдете что-то, что не соответствует этому, чтобы я мог его улучшить!

Ответ 2

Ознакомьтесь с патентом google: http://www.google.com/patents/US7222299

В итоге они содержат хэш-фрагменты текста (предположительно, что-то вроде предложений), а затем искать совпадения с хэшами в предыдущих сообщениях. Супер быстро, и они, вероятно, используют это как вход в алгоритм потоковой передачи. Отличная идея!

Ответ 3

Когда предыдущие электронные письма хранятся на диске или доступны сразу, вы можете проверить все письма, отправить конкретным получателем, чтобы определить, какой текст ответа.

Вы также можете попытаться определить символ кавычки, проверив первый символ последних строк. Нормальный, последние строки всегда начинаются с одного и того же символа.

Когда последние две строки, начинающиеся с символа ifferent, вы можете попробовать первые строки, потому что иногда ответ добавляется в конец текста.

Если вы обнаружили этот символ, вы можете удалить последние строки, начинающиеся с этого символа, до тех пор, пока не будет обнаружена пустая строка или строка, начинающаяся с другого символа.

NOT TESTED и больше похож на псевдокод

    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);
    }

Ответ 4

RegEx отлично работает, за исключением того, что он соответствует тексту, который начинается с Subject и игнорирует все, что идет до "Subject"

Text
-------- Original Message -------- 
<TABLE border="0" cellpadding="0" cellspacing="0">
  <TBODY>
    <TR>
      <TH align="right" valign="baseline">
      // the matcher starts working from here

Ответ 5

От наблюдения за поведением Gmail в этом отношении я наблюдал их стратегию:

  • напишите полную вторую почту.
  • Добавить текст: В [timestamp], [имя отправителя первого имени] < [адрес электронной почты отправителя электронной почты] > написал:
  • Добавить полное электронное письмо. а. Если ваша электронная почта находится в текстовом формате, добавьте " > " перед каждой строкой первого сообщения. б. Если он в HTML, то Gmail дает левое поле, например:

    border-left: 1px solid #CCC; margin: 0px 0px 0px 0.8ex; padding-left: 1ex; таблица стилей пользователя BLOCKQUOTE

    а затем добавляет первый текст электронной почты.

Вы можете перепроектировать это при анализе писем с адреса Gmail. Я не рассматривал других клиентов, но они должны иметь такое же поведение.

Ответ 6

Вы получите почти правку с помощью нескольких строк кода:

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

При необходимости вы можете добавить другие проверки регулярных выражений для почтовых клиентов, которые оставляют разные цитируемые текстовые подписи.