Phân tích cú pháp nội dung email từ câu trả lời được trích dẫn


86

Tôi đang cố gắng tìm ra cách phân tích văn bản của một email từ bất kỳ văn bản trả lời được trích dẫn nào mà nó có thể bao gồm. Tôi nhận thấy rằng thông thường các ứng dụng email sẽ đặt "Vào ngày như vậy và ngày như vậy và viết như vậy" hoặc đặt tiền tố các dòng bằng một dấu ngoặc nhọn. Thật không may, không phải ai cũng làm điều này. Có ai có bất kỳ ý tưởng về cách phát hiện lập trình văn bản trả lời? Tôi đang sử dụng C # để viết trình phân tích cú pháp này.


2
Bạn có bất kỳ may mắn với điều này? Tôi đang tìm cách làm điều tương tự.
steve_c

bất kỳ giải pháp cuối cùng với mẫu mã nguồn đầy đủ làm việc về nó?
Kiquenet

Trích dẫn thực hiện điều này bằng Python
philfreo

Bất cứ ai có thể giúp đỡ cho phiên bản php của nó?
user4271704

Câu trả lời:


60

Tôi đã tìm kiếm nhiều hơn về điều này và đây là những gì tôi đã tìm thấy. Về cơ bản có hai tình huống mà bạn đang làm điều này: khi bạn có toàn bộ luồng và khi bạn không có. Tôi sẽ chia nó thành hai loại:

Khi bạn có chủ đề:

Nếu bạn có toàn bộ chuỗi email, bạn có thể đạt được mức độ đảm bảo rất cao rằng những gì bạn đang xóa thực sự là văn bản được trích dẫn. Có hai cách để làm điều này. Một, bạn có thể sử dụng ID tin nhắn, ID trả lời thư đến và chỉ mục chuỗi để xác định từng thư, thư chính và chủ đề mà thư đó thuộc về. Để biết thêm thông tin về điều này, hãy xem RFC822 , RFC2822 , bài viết thú vị này về phân luồng hoặc bài viết này về phân luồng . Khi bạn đã lắp ráp lại chuỗi, sau đó bạn có thể xóa văn bản bên ngoài (chẳng hạn như dòng Tới, Từ, CC, v.v.) và bạn đã hoàn tất.

Nếu các thư bạn đang làm việc không có tiêu đề, bạn cũng có thể sử dụng đối sánh tương tự để xác định phần nào của email là văn bản trả lời. Trong trường hợp này, bạn đang gặp khó khăn với việc thực hiện đối sánh tương tự để xác định văn bản được lặp lại. Trong trường hợp này, bạn có thể muốn xem xét thuật toán Khoảng cách Levenshtein, chẳng hạn như thuật toán này trên Code Project hoặc thuật toán này .

Không có vấn đề gì, nếu bạn quan tâm đến quy trình phân luồng, hãy xem bản PDF tuyệt vời này về việc tập hợp lại các chuỗi email .

Khi bạn không có chuỗi:

Nếu bạn bị mắc kẹt với chỉ một tin nhắn từ chuỗi, bạn phải cố gắng đoán câu trích dẫn là gì. Trong trường hợp đó, đây là các phương pháp báo giá khác nhau mà tôi đã thấy:

  1. một dòng (như được thấy trong triển vọng).
  2. Dấu ngoặc nhọn
  3. "--- Tin nhắn gốc ---"
  4. "Vào ngày như vậy, tương tự đã viết:"

Xóa văn bản từ đó xuống và bạn đã hoàn tất. Nhược điểm của bất kỳ điều nào trong số này là tất cả đều cho rằng người gửi đặt câu trả lời của họ lên đầu văn bản được trích dẫn và không xen kẽ nó (như kiểu cũ trên internet). Nếu điều đó xảy ra, chúc may mắn. Tôi hy vọng điều này sẽ giúp một số bạn ngoài kia!


32

Trước hết, đây là một nhiệm vụ khó khăn.

Bạn nên thu thập các phản hồi điển hình từ các ứng dụng e-mail khác nhau và chuẩn bị các cụm từ thông dụng chính xác (hoặc bất cứ thứ gì) để phân tích cú pháp. Tôi đã thu thập các phản hồi từ outlook, sấm sét, gmail, apple mail và mail.ru.

Tôi đang sử dụng biểu thức chính quy để phân tích cú pháp phản hồi theo cách sau: nếu biểu thức không khớp, tôi cố gắng sử dụng biểu thức tiếp theo.

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

Để loại bỏ báo giá cuối cùng:

new Regex("^>.*$", RegexOptions.IgnoreCase | RegexOptions.Multiline);

Đây là bộ sưu tập nhỏ của tôi về các phản hồi thử nghiệm (các mẫu được chia cho --- ):

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

Trân trọng, Oleg Yaroshevych


Nếu tôi không biết địa chỉ email thì sao?
harsimranb

@ Shyamal-Parikh này sẽ không làm việc cho email html, nhưng thường là một thông điệp rõ được cũng bao gồm với những thông điệp email
maembe

25

Cảm ơn bạn, Goleg, vì regexes! Thực sự đã giúp. Đây không phải là C #, nhưng đối với những người google ngoài kia, đây là tập lệnh phân tích cú pháp Ruby của tôi:

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

Nó hoạt động khá tốt cho đến nay.


1
Bạn nên đặt một câu hỏi ruby ​​và trả lời nó bằng mã này thay vì đăng nó trên ac # question.
Matthieu

6
@Matthieu, nó không chỉ là một câu hỏi C #, mà còn là một email và câu hỏi phân tích cú pháp email. hoàn toàn phù hợp theo ý kiến ​​của tôi.
Trent

@Trent: nên bỏ thẻ C #.
Matthieu

7
Điều buồn cười là tôi đã tìm thấy câu hỏi này bởi Google cho chủ đề (không phải ngôn ngữ) và tôi thực sự cần triển khai một cái gì đó trong Ruby. Vì vậy, hãy cổ vũ!
bratsche

2
Đây là phản hồi tốt nhất cho đến nay. Regex khá bất khả tri về ngôn ngữ. Cảm ơn cho đăng tải
superluminary

11

Cho đến nay, cách dễ nhất để làm điều này là đặt một điểm đánh dấu vào nội dung của bạn, chẳng hạn như:

--- Vui lòng trả lời trên dòng này ---

Như bạn chắc chắn đã nhận thấy, phân tích cú pháp văn bản được trích dẫn không phải là một nhiệm vụ tầm thường vì các ứng dụng email khác nhau trích dẫn văn bản theo những cách khác nhau. Để giải quyết vấn đề này đúng cách, bạn cần phải tính toán và kiểm tra trong mọi ứng dụng email.

Facebook có thể làm điều này, nhưng trừ khi dự án của bạn có ngân sách lớn, còn không thì có lẽ bạn không thể.

Oleg đã giải quyết vấn đề bằng cách sử dụng regexes để tìm văn bản "Vào ngày 13 tháng 7 năm 2012, lúc 13:09, xxx đã viết:". Tuy nhiên, nếu người dùng xóa văn bản này hoặc trả lời ở cuối email như nhiều người vẫn làm, giải pháp này sẽ không hoạt động.

Tương tự như vậy nếu ứng dụng email sử dụng chuỗi ngày khác hoặc không bao gồm chuỗi ngày thì regex sẽ không thành công.


Cách tiếp cận này không thành công với các câu trả lời trả lời trừ khi bạn đặt dòng đó mỗi khi bạn trả lời.
jpw

1
Vâng, nó có nhược điểm. Nếu người dùng xóa câu trả lời phía trên chuỗi dòng thì câu trả lời của bạn sẽ không thành công. Tôi bắt gặp trường hợp này và gửi cho người dùng một tin nhắn trực tiếp cho họ biết tin nhắn của họ không thành công, kèm theo một liên kết để trả lời qua ứng dụng web. Hầu hết người dùng dường như có thể sử dụng nó mà không gặp quá nhiều khó khăn.
siêu thường

Đây phải là câu trả lời được chấp nhận. Tuy nhiên, tôi sẽ thêm thông tin rằng câu trả lời sẽ không thành công nếu dòng này bị xóa.
Benni

@Benni - có, nó sẽ không thành công nếu dòng bị xóa. Thật không may, không có một cách tiêu chuẩn nào để trích dẫn văn bản trên các ứng dụng email. Trong trường hợp dòng bị xóa, bạn có thể coi tất cả văn bản là một câu trả lời. Tôi không nghĩ rằng một giải pháp hoàn hảo là có thể trong trường hợp này.
siêu thường

@superluminary Ý tôi là, tôi sẽ thêm nó vào dòng. Vì vậy, nó giống như một cái gì đó -- Please reply above this line. DO NOT REMOVE IT! --. Ngoài ra, những gì tôi đã trải nghiệm là nó không phải lúc nào cũng hoạt động vì một số ứng dụng email thêm một xxx wrote on <datetime>:dòng trước toàn bộ báo giá và do đó trước dòng đó. Dòng này có thể được phân tích cú pháp bằng regex, tuy nhiên nó có thể ở các ngôn ngữ khác nhau và ở định dạng khác vì các ứng dụng email khác nhau.
Benni

6

Không có chỉ báo chung nào về phản hồi trong e-mail. Điều tốt nhất bạn có thể làm là cố gắng nắm bắt các mẫu phổ biến nhất và phân tích cú pháp mới khi bạn bắt gặp chúng.

Hãy nhớ rằng một số người chèn câu trả lời bên trong văn bản được trích dẫn (Ví dụ: sếp của tôi trả lời các câu hỏi trên cùng một dòng như tôi đã hỏi họ) vì vậy dù bạn làm gì, bạn có thể mất một số thông tin mà bạn muốn giữ lại.


gmail làm được điều đó ... ít nhất nó có vẻ làm được. Từ những gì tôi nhớ có một số id thread mà không thay đổi giữa gốc và trả lời ...
kenny

gmail có thể thêm '>' cũng như các ứng dụng email khác, nhưng nó không phải là tiêu chuẩn của email và không phải là thứ bạn có thể tin tưởng
3Doubloons

5

Đây là phiên bản C # của mã Ruby của @ hurshagrawal. Tôi không biết rõ về Ruby nên nó có thể bị tắt, nhưng tôi nghĩ tôi đã hiểu đúng.

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

Nếu bạn kiểm soát thư gốc (ví dụ: thông báo từ ứng dụng web), bạn có thể đặt một tiêu đề riêng biệt, có thể nhận dạng tại chỗ và sử dụng tiêu đề đó làm dấu phân cách cho bài đăng gốc.


0

Đây là một giải pháp tốt. Tìm thấy nó sau khi tìm kiếm rất lâu.

Một bổ sung, như đã đề cập ở trên, đây là trường hợp khôn ngoan, vì vậy các biểu thức trên không phân tích cú pháp chính xác các phản hồi gmail và outlook (2010) của tôi, mà tôi đã thêm hai Regex sau. Hãy cho tôi biết nếu có bất kỳ vấn đề nào.

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

Chúc mừng


Bất cứ ai có thể giúp đỡ cho phiên bản php của nó?
user4271704


-1

Tuy nhiên, đây là bài đăng cũ, không chắc bạn có biết github có một lib Ruby trích xuất câu trả lời hay không. Nếu bạn sử dụng .NET, tôi có một .NET tại https://github.com/EricJWHuang/EmailReplyParser


1
Liên kết đến các tài nguyên bên ngoài được khuyến khích, nhưng hãy thêm ngữ cảnh xung quanh liên kết để những người dùng đồng nghiệp của bạn sẽ biết nó là gì và tại sao nó ở đó. Luôn trích dẫn phần có liên quan nhất của một liên kết quan trọng, trong trường hợp trang web mục tiêu không thể truy cập được hoặc vĩnh viễn ngoại tuyến.
pableiros

bạn có đang cập nhật thư viện đó không? Tôi đã tìm kiếm vì thư viện C # không phân tích cú pháp thích hợp một email đơn giản từ Outlook từ Office 365. Sau đó, tôi xem mã nguồn ruby ​​và nhận thấy rằng có một trường hợp thử nghiệm giống hệt nhau trong các trường hợp thử nghiệm của họ nên rõ ràng họ nghĩ rằng họ nên phân tích cú pháp nó.
Greg Veres

-1

Nếu bạn sử dụng API của SigParser.com , nó sẽ cung cấp cho bạn một mảng tất cả các email được chia nhỏ trong một chuỗi trả lời từ một chuỗi văn bản email. Vì vậy, nếu có 10 email, bạn sẽ nhận được văn bản cho tất cả 10 email.

nhập mô tả hình ảnh ở đây

Bạn có thể xem thông số API chi tiết tại đây.

https://api.sigparser.com/

nhập mô tả hình ảnh ở đây

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.