แยกวิเคราะห์เนื้อหาอีเมลจากการตอบกลับที่ยกมา


88

ฉันกำลังพยายามหาวิธีแยกวิเคราะห์ข้อความของอีเมลจากข้อความตอบกลับที่ยกมาซึ่งอาจรวมถึง ฉันสังเกตเห็นว่าโดยปกติโปรแกรมรับส่งเมลจะใส่ "On such and such date so and so written" หรือนำหน้าบรรทัดด้วยวงเล็บมุม น่าเสียดายที่ไม่ใช่ทุกคนที่ทำเช่นนี้ ใครมีความคิดเกี่ยวกับวิธีตรวจหาข้อความตอบกลับโดยใช้โปรแกรมหรือไม่? ฉันใช้ C # เพื่อเขียนโปรแกรมแยกวิเคราะห์นี้


2
คุณมีโชคกับสิ่งนี้หรือไม่? ฉันต้องการทำสิ่งเดียวกัน
steve_c

โซลูชันสุดท้ายที่มีตัวอย่างซอร์สโค้ดแบบเต็มกำลังทำงานอยู่หรือไม่
Kiquenet

Quotequailทำสิ่งนี้ใน Python
philfreo

ใครช่วยรุ่น php ได้ไหม
user4271704

คำตอบ:


60

ฉันค้นหาสิ่งนี้มากขึ้นและนี่คือสิ่งที่ฉันพบ โดยทั่วไปมีสองสถานการณ์ที่คุณกำลังทำสิ่งนี้: เมื่อคุณมีเธรดทั้งหมดและเมื่อคุณไม่มี ฉันจะแบ่งมันออกเป็นสองประเภท:

เมื่อคุณมีเธรด:

หากคุณมีอีเมลทั้งชุดคุณสามารถมั่นใจได้ในระดับสูงว่าสิ่งที่คุณกำลังลบนั้นเป็นข้อความที่ยกมาจริงๆ มีสองวิธีในการทำเช่นนี้ อย่างแรกคุณสามารถใช้ Message-ID, In-Reply-To ID และ Thread-Index ของข้อความเพื่อกำหนดข้อความแต่ละข้อความเป็นพาเรนต์และเธรดที่เป็นของ สำหรับข้อมูลเพิ่มเติมเกี่ยวกับเรื่องนี้ดูRFC822 , RFC2822 , บทความที่น่าสนใจเกี่ยวกับเรื่องนี้เกลียวหรือบทความเกี่ยวกับเกลียว เมื่อคุณประกอบเธรดใหม่แล้วคุณสามารถลบข้อความภายนอก (เช่น To, From, CC, etc ... lines) และเสร็จสิ้น

หากข้อความที่คุณใช้งานไม่มีส่วนหัวคุณยังสามารถใช้การจับคู่ความคล้ายคลึงกันเพื่อกำหนดว่าส่วนใดของอีเมลที่เป็นข้อความตอบกลับ ในกรณีนี้คุณติดอยู่กับการจับคู่ความคล้ายคลึงกันเพื่อกำหนดข้อความที่ซ้ำกัน ในกรณีนี้คุณอาจต้องการที่จะดูในขั้นตอนวิธีการ Levenshtein ระยะทางเช่นนี้ในรหัสโครงการหรืออย่างใดอย่างหนึ่ง

ไม่ว่าคุณจะสนใจกระบวนการเธรดอย่างไรให้ดูPDF ที่ยอดเยี่ยมนี้ในการประกอบเธรดอีเมลอีกครั้ง

เมื่อคุณไม่มีเธรด:

หากคุณติดอยู่กับข้อความเพียงข้อความเดียวจากเธรดคุณจะต้องพยายามเดาว่าข้อความนั้นคืออะไร ในกรณีนี้นี่คือวิธีการเสนอราคาต่างๆที่ฉันเคยเห็น:

  1. เส้น (ตามที่เห็นในแนวโน้ม)
  2. วงเล็บมุม
  3. "---ข้อความต้นฉบับ---"
  4. "ในวันดังกล่าวจึงเขียนว่า:"

ลบข้อความจากตรงนั้นลงไปเท่านี้ก็เสร็จแล้ว ข้อเสียของสิ่งเหล่านี้คือพวกเขาทั้งหมดคิดว่าผู้ส่งใส่คำตอบไว้ด้านบนของข้อความที่ยกมาและไม่ได้แทรกกลาง (เช่นเดียวกับรูปแบบเก่าบนอินเทอร์เน็ต) ถ้าเกิดขึ้นก็ขอให้โชคดี ฉันหวังว่านี่จะช่วยคุณได้บ้าง!


32

ก่อนอื่นนี่เป็นงานที่ยุ่งยาก

คุณควรรวบรวมคำตอบทั่วไปจากไคลเอนต์อีเมลต่างๆและเตรียมนิพจน์ทั่วไปที่ถูกต้อง (หรืออะไรก็ตาม) เพื่อแยกวิเคราะห์ ฉันได้รวบรวมคำตอบจาก 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);

ในการลบใบเสนอราคาในตอนท้าย:

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

ขอแสดงความนับถือ Oleg Yaroshevych


จะเกิดอะไรขึ้นหากฉันไม่ทราบที่อยู่อีเมล
harsimranb

@ Shyamal-Parikh สิ่งนี้ใช้ไม่ได้กับอีเมล html แต่โดยทั่วไปแล้วข้อความธรรมดาจะรวมอยู่ในข้อความอีเมลด้วย
maembe

26

ขอบคุณ Goleg สำหรับ regexes! ช่วยได้จริงๆ นี่ไม่ใช่ C # แต่สำหรับ Googler ที่นั่นนี่คือสคริปต์การแยกวิเคราะห์ 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

มันใช้งานได้ดีจนถึงตอนนี้


1
คุณควรตั้งคำถามเกี่ยวกับทับทิมและตอบด้วยรหัสนี้แทนที่จะโพสต์ใน ac # question
Matthieu

6
@ Matthieu ไม่ใช่แค่คำถาม C # แต่เป็นคำถามเกี่ยวกับอีเมลและอีเมลแยกวิเคราะห์ เกี่ยวข้องทั้งหมดในความคิดของฉัน
Trent

@ Trent: ควรทิ้งแท็ก C # แล้ว
Matthieu

7
สิ่งที่น่าตลกคือฉันพบคำถามนี้โดย Googling สำหรับหัวข้อ (ไม่ใช่ภาษา) และฉันต้องใช้บางอย่างใน Ruby จริงๆ ดังนั้นไชโย!
bratsche

2
นี่คือการตอบสนองที่ดีที่สุดจนถึงตอนนี้ Regex เป็นภาษาที่ไม่เชื่อเรื่องพระเจ้า ขอบคุณสำหรับการโพสต์
superluminary

11

วิธีที่ง่ายที่สุดในการทำเช่นนี้คือการใส่เครื่องหมายในเนื้อหาของคุณเช่น:

--- กรุณาตอบกลับด้านบนบรรทัดนี้ ---

อย่างที่คุณไม่ต้องสงสัยเลยว่าการแยกวิเคราะห์ข้อความที่ยกมาไม่ใช่เรื่องเล็กน้อยเนื่องจากไคลเอนต์อีเมลต่าง ๆ จะอ้างข้อความในรูปแบบต่างๆกัน ในการแก้ปัญหานี้อย่างถูกต้องคุณต้องพิจารณาและทดสอบในโปรแกรมรับส่งเมลทุกตัว

Facebook สามารถทำได้ แต่ถ้าโครงการของคุณไม่มีงบประมาณมากคุณอาจทำไม่ได้

Oleg ได้แก้ปัญหาโดยใช้ regexes เพื่อค้นหาข้อความ "เมื่อวันที่ 13 กรกฎาคม 2012 เวลา 13:09 น. xxx เขียนว่า:" อย่างไรก็ตามหากผู้ใช้ลบข้อความนี้หรือตอบกลับที่ด้านล่างของอีเมลเหมือนที่หลาย ๆ คนทำวิธีนี้จะไม่ได้ผล

ในทำนองเดียวกันหากไคลเอนต์อีเมลใช้สตริงวันที่อื่นหรือไม่รวมสตริงวันที่ regex จะล้มเหลว


วิธีนี้ล้มเหลวเมื่อตอบกลับการตอบกลับเว้นแต่คุณจะวางบรรทัดนั้นทุกครั้งที่ตอบกลับ
jpw

1
ใช่มันมีข้อบกพร่อง หากผู้ใช้ลบการตอบกลับด้านบนสตริงการตอบกลับของคุณจะล้มเหลว ฉันจับกรณีนี้และส่งข้อความโดยตรงถึงผู้ใช้เพื่อแจ้งให้ทราบว่าข้อความของพวกเขาล้มเหลวพร้อมลิงก์สำหรับตอบกลับผ่านเว็บแอป ผู้ใช้ส่วนใหญ่ดูเหมือนจะใช้งานได้โดยไม่มีปัญหามากเกินไป
superluminary

นี่ควรเป็นคำตอบที่ได้รับการยอมรับ อย่างไรก็ตามฉันจะเพิ่มข้อมูลว่าคำตอบจะไม่สำเร็จหากบรรทัดถูกลบออก
Benni

@ Benni - ใช่มันจะล้มเหลวถ้าสายถูกลบออก น่าเสียดายที่ไม่มีวิธีมาตรฐานเดียวในการอ้างอิงข้อความในโปรแกรมรับส่งเมล ในกรณีที่บรรทัดถูกลบคุณอาจถือว่าข้อความทั้งหมดเป็นการตอบกลับ ฉันไม่คิดว่าจะสามารถแก้ปัญหาที่สมบูรณ์แบบได้ในกรณีนี้
superluminary

@superluminary ฉันหมายถึงฉันจะเพิ่มในบรรทัด มันก็เป็นอย่าง-- Please reply above this line. DO NOT REMOVE IT! --นั้น นอกจากนี้สิ่งที่ฉันพบคือมันใช้ไม่ได้เสมอไปเนื่องจากไคลเอนต์อีเมลบางรายเพิ่มxxx wrote on <datetime>:บรรทัดก่อนใบเสนอราคาทั้งหมดและก่อนบรรทัดนั้น บรรทัดนี้สามารถแยกวิเคราะห์ด้วย regex ได้อย่างไรก็ตามอาจเป็นภาษาที่แตกต่างกันและอยู่ในรูปแบบที่แตกต่างกันเนื่องจากไคลเอนต์อีเมลต่างกัน
Benni

7

ไม่มีตัวบ่งชี้สากลของการตอบกลับในอีเมล สิ่งที่ดีที่สุดที่คุณทำได้คือพยายามหารูปแบบที่พบบ่อยที่สุดและแยกวิเคราะห์รูปแบบใหม่เมื่อคุณเจอ

โปรดทราบว่าบางคนใส่คำตอบไว้ในข้อความที่ยกมา (เช่นเจ้านายของฉันตอบคำถามในบรรทัดเดียวกับที่ฉันถาม) ดังนั้นไม่ว่าคุณจะทำอะไรคุณอาจสูญเสียข้อมูลบางอย่างที่คุณต้องการเก็บไว้


gmail ก็ทำ ... อย่างน้อยก็น่าจะทำได้ จากสิ่งที่ฉันจำได้มีรหัสเธรดบางตัวที่ไม่เปลี่ยนแปลงระหว่าง orginal และการตอบกลับ ...
kenny

gmail อาจเพิ่ม '>' เช่นเดียวกับโปรแกรมรับส่งอีเมลอื่น ๆ แต่ไม่ใช่มาตรฐานของอีเมลและไม่ใช่สิ่งที่คุณสามารถวางใจได้
วางใจได้

6

นี่คือรหัส Ruby ของ @ hurshagrawal เวอร์ชัน 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();
}

3

หากคุณควบคุมข้อความต้นฉบับ (เช่นการแจ้งเตือนจากเว็บแอปพลิเคชัน) คุณสามารถใส่ส่วนหัวที่แตกต่างและระบุตัวตนได้และใช้เป็นตัวคั่นสำหรับโพสต์ต้นฉบับ


0

นี่เป็นทางออกที่ดี พบมันหลังจากค้นหามานาน

นอกจากนี้อีกหนึ่งอย่างตามที่กล่าวไว้ข้างต้นนี่เป็นกรณีที่ชาญฉลาดดังนั้นนิพจน์ข้างต้นจึงไม่ได้แยกวิเคราะห์การตอบกลับ Gmail และ Outlook (2010) ของฉันอย่างถูกต้องซึ่งฉันได้เพิ่ม Regex สองรายการต่อไปนี้ แจ้งให้เราทราบสำหรับปัญหาใด ๆ

//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),

ไชโย


ใครช่วยรุ่น php ได้ไหม
user4271704

ตรวจสอบสิ่งนี้สำหรับเวอร์ชัน php stackoverflow.com/questions/14916618/… github.com/willdurand/EmailReplyParser
FullStackDev

-1

มันเป็นโพสต์เก่า แต่ไม่แน่ใจว่าคุณทราบหรือไม่ว่า github มีRuby lib ที่แยกการตอบกลับ ถ้าคุณใช้. NET ฉันมี. NET อยู่ที่https://github.com/EricJWHuang/EmailReplyParser


1
ขอแนะนำให้ใช้ลิงก์ไปยังแหล่งข้อมูลภายนอก แต่โปรดเพิ่มบริบทรอบ ๆ ลิงก์เพื่อให้ผู้ใช้รายอื่นได้ทราบว่ามันคืออะไรและเหตุใดจึงมี อ้างอิงส่วนที่เกี่ยวข้องที่สุดของลิงก์ที่สำคัญเสมอในกรณีที่ไซต์เป้าหมายไม่สามารถเข้าถึงได้หรือออฟไลน์ถาวร
pableiros

คุณกำลังปรับปรุงห้องสมุดนั้นให้ทันสมัยอยู่เสมอหรือไม่? ฉันมาค้นหาเพราะไลบรารี C # แยกวิเคราะห์อีเมลธรรมดาจาก Outlook จาก Office 365 ไม่ถูกต้องจากนั้นฉันก็ดูซอร์สโค้ดทับทิมและพบว่ามีกรณีทดสอบที่เหมือนกันในกรณีทดสอบของพวกเขาดังนั้นพวกเขาจึงคิดว่าควรแยกวิเคราะห์ มัน.
Greg Veres

-2

หากคุณใช้API ของSigParser.comจะให้อาร์เรย์ของอีเมลที่แยกย่อยทั้งหมดในชุดข้อความตอบกลับจากสตริงข้อความอีเมลเดียว ดังนั้นหากมีอีเมล 10 ฉบับคุณจะได้รับข้อความสำหรับอีเมลทั้ง 10 ฉบับ

ใส่คำอธิบายภาพที่นี่

คุณสามารถดูข้อมูลจำเพาะ API โดยละเอียดได้ที่นี่

https://api.sigparser.com/

ใส่คำอธิบายภาพที่นี่

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.