Я пытаюсь выяснить, как разобрать текст письма из любого цитируемого текста ответа, который он может включить. Я заметил, что обычно почтовые клиенты будут помещать "В такую и такую дату так и так написано" или префикс строк с помощью угловой скобки. К сожалению, не все это делают. Кто-нибудь имеет представление о том, как программно обнаруживать текст ответа? Я использую С# для написания этого синтаксического анализатора.
Разбирайте содержимое электронной почты из указанного ответа
Ответ 1
Я много сделал для этого и нашел то, что нашел. Существуют две ситуации, в которых вы делаете это: когда у вас есть весь поток, а когда нет. Я разбиваю его на две категории:
Когда у вас есть поток:
Если у вас есть целая серия писем, вы можете достичь очень высокого уровня уверенности в том, что то, что вы удаляете, - это фактически цитируемый текст. Есть два способа сделать это. Во-первых, вы можете использовать сообщение Message-ID, In-Reply-To ID и Thread-Index для определения отдельного сообщения, его родительского элемента и потока, к которому он принадлежит. Для получения дополнительной информации об этом см. RFC822, RFC2822, эта интересная статья о потоковом, или эта статья о потоковом. После повторной сборки потока вы можете удалить внешний текст (например, To, From, CC и т.д.), И все готово.
Если в сообщениях, с которыми вы работаете, нет заголовков, вы также можете использовать подобие, чтобы определить, какие части письма являются ответом. В этом случае вы застряли с совпадением подобия, чтобы определить повторяющийся текст. В этом случае вы можете захотеть изучить алгоритм расстояния Levenshtein, например this один в проекте кода или этот.
Независимо от того, что, если вас интересует процесс потоковой передачи, посмотрите этот отличный PDF файл для повторной сборки потоков электронной почты.
Если у вас нет потока:
Если вы застряли только с одним сообщением из потока, вам нужно попытаться угадать, какова цитата. В этом случае здесь приведены различные методы котировок, которые я видел:
- строка (как видно в Outlook).
- Угловые скобки
- "--- Оригинальное сообщение ---"
- "В такой-то день, так и так писал:"
Снимите текст с него, и все готово. Недостатком любого из них является то, что все они предполагают, что отправитель отправил свой ответ поверх цитируемого текста и не чередовал его (как и старый стиль в Интернете). Если это произойдет, удачи. Я надеюсь, что это поможет некоторым из вас там!
Ответ 2
Прежде всего, это сложная задача.
Вы должны собирать типичные ответы от разных почтовых клиентов и готовить правильные регулярные выражения (или что-то еще) для их анализа. Я собрал ответы от 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: [email protected] [mailto:[email protected]]
Sent: Tuesday, January 13, 2009 1:27 PM
----
2008/12/26 <[email protected]>
> text
----
[email protected] wrote:
> text
----
[email protected] wrote: text
text
----
2009/1/13 <[email protected]>
> text
----
[email protected] wrote: text
text
----
2009/1/13 <[email protected]>
> text
> text
----
2009/1/13 <[email protected]>
> text
> text
----
[email protected] wrote:
> text
> text
<response here>
----
--- On Fri, 23/1/09, [email protected] <[email protected]> wrote:
> text
> text
С наилучшими пожеланиями, Олег Ярошевич
Ответ 3
Спасибо, Goleg, для регулярных выражений! Действительно помог. Это не С#, но для googlers там, здесь мой анализ Ruby 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
До сих пор он работал очень хорошо.
Ответ 4
Самый простой способ сделать это - разместить маркер в своем контенте, например:
--- Пожалуйста, ответьте выше этой строки ---
Как вы, несомненно, заметили, разбор цитированного текста не является тривиальной задачей, поскольку разные почтовые клиенты цитируют текст по-разному. Чтобы решить эту проблему должным образом, вам нужно учитывать и тестировать в каждом почтовом клиенте.
Facebook может это сделать, но если у вашего проекта большой бюджет, вы, вероятно, не сможете.
Олег решил проблему с помощью регулярных выражений, чтобы найти "13 июля 2012 года, в 13:09, xxx написал:" текст. Однако, если пользователь удаляет этот текст или отвечает в нижней части письма, как это делают многие люди, это решение не будет работать.
Аналогично, если почтовый клиент использует другую строку даты или не содержит строку даты, это приведет к ошибке.
Ответ 5
В электронном письме нет универсального индикатора ответа. Лучшее, что вы можете сделать, это попытаться поймать наиболее распространенные и проанализировать новые шаблоны, когда вы столкнетесь с ними.
Имейте в виду, что некоторые люди вставляют ответы внутри цитируемого текста (например, мой босс отвечает на вопросы в той же строке, что и я их спросил), поэтому, что бы вы ни делали, вы могли потерять некоторую информацию, которую вы хотели бы сохранить.
Ответ 6
Вот моя версия С# для кода Ruby @hurshagrawal. Я не очень хорошо знаю 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();
}
Ответ 7
Если вы контролируете исходное сообщение (например, уведомления из веб-приложения), вы можете поместить отдельный идентифицируемый заголовок на место и использовать его как разделитель для исходного сообщения.
Ответ 8
Это хорошее решение. Нашел его после долгого поиска.
Одно из добавлений, как упоминалось выше, это случайное, поэтому приведенные выше выражения не правильно анализировали мои ответы gmail и outlook (2010), для которых я добавил следующие два Regex (s). Сообщите мне о любых проблемах.
//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),
Приветствия
Ответ 9
Это старый пост, однако, не уверен, что вы знаете, что github Ruby lib извлекает ответ. Если вы используете .NET, у меня есть .NET в https://github.com/EricJWHuang/EmailReplyParser