16

メールを解析しています。メールへの返信が表示されたら、引用されたテキストを削除して、前のメールにテキストを追加できるようにしたいと思います (返信であっても)。

通常、次のように表示されます。

最初のメール (会話の開始)

This is the first email

2 通目のメール (1 通目に返信)

This is the second email

Tim said:
This is the first email

この出力は、「これは 2 番目のメールです」のみです。電子メール クライアントによってテキストの引用方法は異なりますが、新しい電子メール テキストのみを取得する方法があれば、それも問題ありません。

4

6 に答える 6

15

次の正規表現を使用して、引用されたテキストのリードインを照合します (最後の正規表現が重要です)。

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

いくつかの点で、これはやり過ぎ (そして遅いかもしれません!) であることはわかっていますが、かなりうまく機能します。これと一致しないものを見つけた場合はお知らせください。改善できるようにします。

于 2010-07-08T04:09:31.270 に答える
7

これに関する Google の特許を確認してください: http://www.google.com/patents/US7222299

要約すると、テキストの一部 (おそらく文のようなもの) をハッシュし、前のメッセージのハッシュと一致するものを探します。超高速で、おそらくこれをスレッド化アルゴリズムへの入力としても使用します。何て素晴らしいアイデアなんだ!

于 2013-08-09T16:16:35.193 に答える
2

正規表現は、件名から始まるテキストに一致し、「件名」の前にあるすべてを無視することを除いて、正常に機能します

Text
-------- Original Message -------- 
<TABLE border="0" cellpadding="0" cellspacing="0">
  <TBODY>
    <TR>
      <TH align="right" valign="baseline">
      // the matcher starts working from here
于 2011-04-11T15:45:53.743 に答える
2

以前の電子メールがディスクに保存されている場合、または使用可能な somwhow の場合、すべてのメールをチェックし、特定の受信者から送信されたメールを確認して、どれが応答テキストであるかを判断できます。

最後の行の最初の文字をチェックして、引用文字を判別することもできます。通常、最後の行は常に同じ文字で始まります。

最後の 2 行が異なる文字で始まる場合は、最初の行を試すことができます。これは、テキストの最後に回答が追加されることがあるためです。

これらの文字が検出された場合、空の行または別の文字で始まる行が検出されるまで、この文字で始まる最後の行を削除できます。

テストされておらず、疑似コードに似ています

    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);
    }
于 2010-03-05T08:29:59.933 に答える
1

数行のコードでほぼ正しくなります。

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

必要に応じて、別の引用テキスト署名を残す電子メール クライアント用に他の正規表現チェックを追加できます。

于 2010-03-07T01:43:01.413 に答える
1

この点に関する Gmail の動作を観察することで、Gmail の戦略を観察しました。

  1. 完全な 2 番目のメールを書きます。
  2. 次のようなテキストを追加します: [タイムスタンプ] に [最初の電子メール送信者名] <[最初の電子メール送信者の電子メールアドレス]> が書きました:
  3. 完全な最初の電子メールを追加します。を。メールがプレーン テキストの場合は、最初のメールの各行の前に「>」を追加します。b. HTML の場合、Gmail は次のような左側の余白を与えます。

    border-left: 1px ソリッド #CCC; マージン: 0px 0px 0px 0.8ex; パディング左: 1ex; ユーザー エージェント スタイルシート ブロック引用

    次に、最初の電子メールのテキストを追加します。

Gmail アドレスからのメールを解析するときに、これをリバース エンジニアリングできます。私は他のクライアントを調べていませんが、同じ動作をするはずです。

于 2010-03-05T08:33:37.493 に答える