|
Компьютерный форум OSzone.net » Программирование, базы данных и автоматизация действий » Программирование и базы данных » Теория - Расчленяем почту |
|
Теория - Расчленяем почту
|
![]() Ветеран Сообщения: 1180 |
Привет! Помоги решить задачу (нужен подход):
Есть электронное письмо. Нужно:
Теоретически письмо может быть составлено любым почтовым клиентом. С визиткой ещё как-то можно придумать, например искать по списку "Best regards" не дальше N слов от e-mail отправителя. С остальным как-то затрудняюсь |
|
Отправлено: 20:27, 09-11-2013 |
![]() Ветеран Сообщения: 1180
|
Профиль | Отправить PM | Цитировать первый эксперимент. В принципе нормально себя показывает когда искомая строка гарантировано есть в тексте. Когда нет или содержит небольшие ошибки, то находит не всегда то, что хотелось бы. Хотя придраться сложно, текст действительно похож. И появилась мысль, как выдирать репосты (по сути репост - это плагиат)
#include <iostream> #include <fstream> #include <string> #include <algorithm> #include <functional> #include <numeric> #include <list> #include <valarray> using namespace std; template<typename Iterator2, typename Iterator1, typename OutputIterator, typename Value, typename Plus, typename Times> void corelate(Iterator2 sample_first, Iterator2 sample_last, Iterator1 data_first, OutputIterator result_first, OutputIterator result_last, Value init, Plus plus, Times times) { for(; result_first!=result_last; ++data_first,++result_first) { *result_first = inner_product(sample_first, sample_last, data_first, init, plus, times); } } template<typename T> unsigned fuzzy_match(T const& a, T const& b) { return a==b ? 100 : 0; } template<> unsigned fuzzy_match(string const& a, string const& b) { string::size_type a_size=a.size(), b_size=b.size(); plus<unsigned> plus; unsigned accum; if (a_size && b_size) { switch(a_size-b_size) { case 0: accum = inner_product(a.begin(), a.end(), b.begin(), unsigned(), plus, fuzzy_match<string::value_type>) + inner_product(b.begin()+1, b.end(), a.begin(), unsigned(), plus, fuzzy_match<string::value_type>) + inner_product(a.begin()+1, a.end(), b.begin(), unsigned(), plus, fuzzy_match<string::value_type>); break; case 1: accum = inner_product(b.begin(), b.end(), a.begin(), unsigned(), plus, fuzzy_match<string::value_type>) + inner_product(b.begin(), b.end(), a.begin()+1, unsigned(), plus, fuzzy_match<string::value_type>); break; case ~0u: accum = inner_product(a.begin(), a.end(), b.begin(), unsigned(), plus, fuzzy_match<string::value_type>) + inner_product(a.begin(), a.end(), b.begin()+1, unsigned(), plus, fuzzy_match<string::value_type>); break; default: return 0; } return 2*accum / (a_size + b_size); } return 0; } template<typename T> unsigned fuzzy_search(list<T> const& sample, list<T> const& source, valarray<unsigned> &match, unsigned spread_size, unsigned const *spread_sensitivity) { typename list<T>::size_type sample_size=sample.size(), source_size=source.size(); if (source_size >= sample_size + spread_size) { match.resize(source_size - sample_size); unsigned *r1 = &match[0], *r2 = &match[match.size()]; corelate(sample.begin(), sample.end(), source.begin(), r1, r2, unsigned(), plus<unsigned>(), fuzzy_match<T>); corelate(spread_sensitivity+0, spread_sensitivity+spread_size, r1, r1, r2-spread_size, unsigned(), plus<unsigned>(), multiplies<unsigned>()); return match.max(); } return 0; } void load_words(const char *name, list<string>& result) { filebuf in; in.open(name, ios_base::in); string word; int c = in.sbumpc(); for (; c!=-1; c=in.sbumpc()) { if (192<=c || isalpha(c)) { word.clear(); do { word.push_back(c|32), c=in.sbumpc(); } while (192<=c || isalpha(c)); result.push_back(word); } } } int main() { static unsigned const spread_size = 1; static unsigned const accept_percent = 90; static unsigned const spread[] = {1,1,1,1,1,1,1,1}; list<string> sample, text; valarray<unsigned> match; unsigned threshold; load_words("sample.txt", sample); load_words("text.txt", text); threshold = accept_percent*fuzzy_search(sample, text, match, spread_size, spread)/100; unsigned sample_size = sample.size(); unsigned match_pos = 0; list<string>::iterator pos = text.begin(); for(; match_pos!=match.size(); ++match_pos,++pos) { if (threshold < match[match_pos]) { list<string>::iterator word = pos; cout << match[match_pos]/sample_size << "%:"; for(unsigned n=sample_size; n; ++word,--n) { cout << " " << *word; } cout << "\n"; } } return 0; } ответ получается понятней, когда spread_size = 1 исходный файл - text.txt что искать - sample.txt понимает английские и русские буквы в 1251 |
Отправлено: 20:51, 10-11-2013 | #2 |
Для отключения данного рекламного блока вам необходимо зарегистрироваться или войти с учетной записью социальной сети. Если же вы забыли свой пароль на форуме, то воспользуйтесь данной ссылкой для восстановления пароля. |
![]() Ветеран Сообщения: 1180
|
Профиль | Отправить PM | Цитировать В общем, придумал способ находить цитаты (и подписи, если считать их цитатами), второе приближение.
Задача №1: найти все репосты. Решение: ищем общую последовательность максимальной длины, помечаем, вырезаем, разделяем найденной частью один из списков на два. Для каждой получившихся частей повторяем задачу заново. Задача №2: в 2-х списках строк найти общую последовательность максимальной длины. Решаем как задачу динамического программирования. Пусть список sample - тот, из которого ищем цитаты, text - тот в котором ищем. Управление: позиция в sample, с которой начинается цитата. Состояние: лучшая длина + начало цитаты, текущая длина. Т.о. возможен однопроходной алгоритм, количество сравнений - N*M, где N и M - длины списков. Если считать цитаты достаточно редкими, то можно уменьшить расходуемую память и ускорить обработку за счёт использования хеш-мапов строк на состояния. Если требуется нечёткое сравнение, то строки предварительно обрабатываются канонанизатором (т.е. перекодируются, выкидываются части, не имеющие значения) Вероятно можно переформулировать задачу так, чтобы на выходе сразу получался разбитый цитатами список. Какие ещё могут быть варианты решения задачи? |
Отправлено: 11:48, 12-11-2013 | #3 |
Ветеран Сообщения: 1813
|
Профиль | Отправить PM | Цитировать Цитата pva:
|
|
Отправлено: 14:59, 12-11-2013 | #4 |
![]() Ветеран Сообщения: 1180
|
Профиль | Отправить PM | Цитировать Честно говоря, я думал что значки ">>" проставляет почтовый клиент. В письмах, которые я взял для анализа, я обнаружил кроме html-ных частей ещё текстовые копии (для старых почтовых клиентов), там такие значки проставляются. Но не со всеми письмами прокатывает.
В общем, я провёл эксперименты со вторым приближением. За образец взял два "очень длинных письма" - два рассказа братьев Стругацких, с разделением по словам, а не по строкам, у слов отрезаются окончания (такой канонизатор). Время измеряно для отладочной сборки. longest match (10): библиотек ладошек http palm com ладошк солнц карманны компьютеры аркад sample 72835 words text 40581 words took 120 secs Делаем улучшение(1): составляем map<string,unsigned> из слов. В качестве слов используем указатели на слова, сравнение указатеелй как чисел (в итоге полностью исключаем сравнение слов, имеем идеальный хеш), но можем потерять на загрузке (составление словаря). loaded at 0 secs sample 72835 words text 40581 words took 65 secs longest match (10): библиотек ладошек http palm com ладошк солнц карманны компьютеры аркад Другое улучшение(2): Теперь считаем цитаты редкими и составляем map слова на список его вхождений. Убираем хеш, т.е. снова сравниваем строки. loaded at 0 secs sample 72835 words text 40581 words took 1 secs longest match (10): библиотек ладошек http palm com ладошк солнц карманны компьютеры аркад Теперь решаем задачу "найти все цитаты". Для этого заметим, что мы их фактически все и находим, находя максимальную. Отличие только в том, как производится выбор лучшего решения из последнего состояния. Вместо вывода на экран самой длинной цепочки, мы выводим все цепочки в порядке убывания длины. Причём после вывода цепочки удаляем её состояния, избегая тем самым пересечения. Любопытно выглядят цепочки из 3-5 слов. По сути это любимые выражения автора, стиль его разговора. Можно использовать для анализа личности (сравнив несколько писем). Мне понравилась фраза (если правильно помню) "вот уже пять лет как". т.о. полная задача решена за лучшее время меньше 1 сек. Если считать подписи цитатами подписей, проверять цитирование письмом не только прошлого письма, но и подписи отправителя, то вроде как задача решается. Внимание, вопрос для разработчиков архиваторов: что будет, если найти все цитаты письма самим себя (по сути все повторения)?.... Правильно! письмо полностью себя цитирует! Ещё одно возможное применение - diff, который находит не только отличия, но и копипасты. В принципе задачу можно считать решённой; остаются вопросы с ложными срабатываниями, когда за цитирование будет принят плохой стиль письма. |
|
Отправлено: 11:37, 13-11-2013 | #5 |
![]() Ветеран Сообщения: 1180
|
Профиль | Отправить PM | Цитировать Примеры схожих в двух произведениях фраз:
longest match (5): разобра можн был тольк отдельны longest match (5): отдавал себ отч то чт longest match (5): наскольк эт возможн пр наш longest match (5): как раз тот момент когд longest match (4): знаю как эт делаетс longest match (4): вдруг пришл голов чт longest match (4): ег покидал ощущени чт longest match (4): вс вид сво изображ longest match (4): можн был предположи чт longest match (4): вдруг пришл голов чт longest match (4): чт вс эт врем longest match (4): однак ясн был чт longest match (4): эт был сам дел longest match (4): кра глаз вид чт longest match (4): можн был подума чт longest match (4): вс дел то чт longest match (4): почувствовал чт вот сейчас longest match (4): знаю тольк чт мн longest match (4): дл тог чтобы убива longest match (4): мож бы вс дел longest match (4): тольк дл тог чтобы longest match (4): вс эт врем он longest match (4): некотор врем сид неподвижн longest match (4): человек мож бы даж longest match (4): знае чт эт так longest match (4): ем был вс равн longest match (4): сраз понял чт эт longest match (4): совершенн невозможн был представи longest match (4): невозможн был представи себ longest match (4): сраз понял чт эт longest match (4): сраз понял чт эт longest match (4): был совершенн ясн чт longest match (4): откинулс спинк кресл вот longest match (4): был совершенн ясн чт longest match (4): можн был спокойн совестью longest match (4): уж прост пот чт longest match (4): взял папк под мышк longest match (4): простит как вас зовут |
Отправлено: 13:17, 13-11-2013 | #6 |
![]() |
Участник сейчас на форуме |
![]() |
Участник вне форума |
![]() |
Автор темы |
![]() |
Сообщение прикреплено |
| |||||
Название темы | Автор | Информация о форуме | Ответов | Последнее сообщение | |
2008 R2 - Помогите настроить почту... | Вовка_Морковка | Windows Server 2008/2008 R2 | 1 | 14-06-2013 16:07 | |
Интерфейс - IE не видит почту | IZOprogman | Microsoft Windows 7 | 5 | 10-09-2012 10:17 | |
Взломали мою почту на narod.ru, скажите как восстановить мою почту? | THEDOGG | Хочу все знать | 8 | 20-08-2012 08:56 | |
2003/XP/2000 - Не принимает почту... | helden | Microsoft Office (Word, Excel, Outlook и т.д.) | 3 | 22-09-2011 15:55 | |
Интернет через почту | DYURIK | Сетевые технологии | 12 | 13-10-2003 12:42 |
|