90

電子メールに含まれる可能性のある引用された返信テキストから、電子メールのテキストを解析する方法を見つけようとしています。通常、メール クライアントは「On such and such date so and so written」を挿入するか、行の前に山かっこを付けることに気付きました。残念ながら、誰もがこれを行うわけではありません。プログラムで返信テキストを検出する方法について誰か考えがありますか? このパーサーを作成するために C# を使用しています。

4

10 に答える 10

61

私はこれについてさらに多くの検索を行い、ここに私が見つけたものがあります。これを行う状況は基本的に 2 つあります。スレッド全体がある場合とない場合です。この 2 つのカテゴリに分けて説明します。

スレッドがある場合:

一連の電子メール全体があれば、削除しようとしているものが実際に引用されたテキストであることを非常に高いレベルで保証できます。これには 2 つの方法があります。1 つは、メッセージの Message-ID、In-Reply-To ID、および Thread-Index を使用して、個々のメッセージ、その親、およびそのメッセージが属するスレッドを判別することです。詳細については、RFC822RFC2822スレッドに関する興味深い記事、またはスレッドに関する記事を参照してください。スレッドを再構成したら、外部テキスト (To、From、CC などの行) を削除して完了です。

処理しているメッセージにヘッダーがない場合は、類似性マッチングを使用して、メールのどの部分が返信テキストであるかを判断することもできます。この場合、繰り返されるテキストを決定するために類似性マッチングを行うことに行き詰まっています。この場合、Code Projectの this oneやthis oneなどのレーベンシュタイン距離アルゴリズムを調べることができます。

いずれにせよ、スレッド化プロセスに興味がある場合は、電子メール スレッドの再構築に関するこのすばらしい PDF を確認してください。

スレッドがない場合:

スレッドからのメッセージが 1 つしかない場合は、その引用が何であるかを推測する必要があります。その場合、私が見たさまざまな引用方法は次のとおりです。

  1. 線 (見通しで見られるように)。
  2. 角括弧
  3. " - -オリジナルメッセージ - -"
  4. 「何々の日、何々が書いた:」

そこからテキストを削除すれば完了です。これらのいずれかの欠点は、送信者が引用されたテキストの上に返信を置き、それをインターリーブしなかったと想定していることです (インターネットの古いスタイルのように)。もしそうなら、幸運を祈ります。これがあなたの何人かを助けることを願っています!

于 2008-11-10T22:35:28.753 に答える
34

まず第一に、これはトリッキーな作業です。

さまざまな電子メール クライアントから典型的な応答を収集し、それらを解析するための正しい正規表現 (または何でも) を準備する必要があります。Outlook、Thunderbird、Gmail、Apple メール、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 <test@test.com>

>  text
----
test@test.com wrote:
> text
----
      test@test.com wrote:         text
text
----
2009/1/13 <test@test.com>

>  text
----
 test@test.com wrote:         text
 text
----
2009/1/13 <test@test.com>

> text
> text
----
2009/1/13 <test@test.com>

> text
> text
----
test@test.com wrote:
> text
> text
<response here>
----
--- On Fri, 23/1/09, test@test.com <test@test.com> wrote:

> text
> text
于 2009-01-23T19:33:34.897 に答える
26

Thank you, Goleg, for the regexes! Really helped. This isn't C#, but for the googlers out there, here's my Ruby parsing script:

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

It's worked pretty well so far.

于 2011-09-11T03:02:08.243 に答える
12

これを行う最も簡単な方法は、次のようなマーカーをコンテンツに配置することです。

--- この行の上に返信してください ---

お気付きのように、引用されたテキストを解析することは簡単な作業ではありません。さまざまな電子メール クライアントがさまざまな方法でテキストを引用しているからです。この問題を適切に解決するには、すべての電子メール クライアントを考慮してテストする必要があります。

Facebook はこれを行うことができますが、プロジェクトに多額の予算がない限り、おそらく不可能です。

Oleg は、正規表現を使用して「On 13 Jul 2012, at 13:09, xxx written:」というテキストを見つけるために問題を解決しました。ただし、多くの人がそうであるように、ユーザーがこのテキストを削除したり、電子メールの最後に返信したりすると、この解決策は機能しません。

同様に、電子メール クライアントが別の日付文字列を使用している場合、または日付文字列が含まれていない場合、正規表現は失敗します。

于 2012-07-13T13:41:49.820 に答える
7

電子メールの返信の普遍的な指標はありません。最善の方法は、最も一般的なパターンをキャッチして、新しいパターンに遭遇したときに解析することです。

引用文の中に返信を挿入する人もいることに注意してください (たとえば、私の上司は、私が尋ねたのと同じ行で質問に答えます)。

于 2008-11-10T19:08:02.620 に答える
6

@hurshagrawal の Ruby コードの C# バージョンを次に示します。私は 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();
}
于 2013-02-15T21:29:49.937 に答える
3

元のメッセージ (Web アプリケーションからの通知など) を制御する場合は、明確で識別可能なヘッダーを配置し、それを元の投稿の区切り文字として使用できます。

于 2011-06-01T23:40:23.817 に答える