Название: [РЕШЕНО]Нечеткое сравнение строк
Отправлено: Vitto74 от Февраль 19, 2010, 22:51
Дорого времени суток. При создании электронного учебника встала потребность организовать поиск по глоссарию (только по заголовкам). Для этого я решил использовать алгоритм нечеткого сравнения строк, взятый отсюда http://www.delphikingdom.com/asp/viewitem.asp?catalogid=722 После перевода получилось следующее: struct retCount{ int lngSubRows; int lngCountLike; };
retCount Matching(QString InputA, QString InputB, int lngLen) { retCount TempRet; int PosStrB; int PosStrA; QString StrA; QString StrB; QString StrTempA; QString StrTempB; QString StrInputA = InputA.toLower(); QString StrInputB = InputB.toLower();
StrA = StrInputA; StrB = StrInputB;
for ( PosStrA = 1; PosStrA <= (StrA.length() - lngLen + 1); ++PosStrA){ StrTempA = StrA.mid(PosStrA, lngLen); PosStrB = 1; for (PosStrB = 1; PosStrB <= (StrB.length() - lngLen + 1); ++PosStrB){ StrTempB = StrB.mid(PosStrB, lngLen); if (StrTempA == StrTempB){ TempRet.lngCountLike++; break; } } TempRet.lngSubRows++; } return TempRet; }
int IndistinctMatching(QString InputMatching, QString InputStandart, int MaxMatching = 4) { QString strInputMatching = InputMatching.toLower(); QString strInputStandart = InputStandart.toLower(); retCount gret; retCount tret; int lngCurLen; //текущая длина подстроки //если не передан какой-либо параметр, то выход if ((MaxMatching == 0) || (strInputMatching.length() == 0) || (strInputStandart.length() == 0)){ return 0; }
gret.lngCountLike = 0; gret.lngSubRows = 0; // Цикл прохода по длине сравниваемой фразы for (lngCurLen = 1; lngCurLen <= MaxMatching; ++lngCurLen){ //Сравниваем строку A со строкой B tret = Matching(strInputMatching, strInputStandart, lngCurLen); gret.lngCountLike = gret.lngCountLike + tret.lngCountLike; gret.lngSubRows = gret.lngSubRows + tret.lngSubRows; //Сравниваем строку B со строкой A tret = Matching(strInputStandart, strInputMatching, lngCurLen); gret.lngCountLike = gret.lngCountLike + tret.lngCountLike; gret.lngSubRows = gret.lngSubRows + tret.lngSubRows; }
if (gret.lngSubRows == 0){ return 0; } //избыточность сделал для удобства отладки float rez = ((float)gret.lngCountLike/(float)gret.lngSubRows); rez = rez*100; return (int)rez; }
Но эта функция жутко глючит: на одинаковых параметрах несколько раз выдавала разные результаты. Более того функция должна выдавать процент совпадения, а она выдает числа не меньше 100, а иногда и несколько тысяч. Вставив код во Lazarus получил более вменяемые. но тоже не верные результаты. Жду предложений. PS облазил гугл, но функцию на C++ не нашел.
Название: Re: Нечеткое сравнение строк
Отправлено: BlackTass от Февраль 19, 2010, 23:29
я бы порекомендовал поискать что-нибудь по морфологии. Ваш алгоритм никак не привязан к особенностям языка. Если же надо сделать просто нечеткое сравнение двух неважно-каких строковых данных, то имхо какой-нибудь soundex или подобные алгоритмы вполне подойдут.
Название: Re: Нечеткое сравнение строк
Отправлено: Vitto74 от Февраль 20, 2010, 13:20
Причины глюков найдены! Два дня не мог понять причину глюков, а главное - почему на одних данных выдает разные результаты! Я забыл инициализировать переменные - в pascal они инициализируются нулями автоматически, а в C++ нет. Вот код исправленных функций /*MaxMatching - максимальная длина подстроки (достаточно 3-4) strInputMatching - сравниваемая строка strInputStandart - строка-образец
Сравнивание без учета регистра if (IndistinctMatching(4, "поисковая строка", "оригинальная строка - эталон") > 40) ... */ struct retCount{ int lngSubRows; int lngCountLike; };
retCount Matching(QString InputA, QString InputB, int lngLen) { retCount TempRet; TempRet.lngCountLike = 0; TempRet.lngSubRows = 0; int PosStrB = 0; int PosStrA = 0; QString StrTempA = ""; QString StrTempB = ""; QString StrInputA = InputA.toLower(); QString StrInputB = InputB.toLower();
QString StrA = StrInputA; QString StrB = StrInputB;
for ( PosStrA = 1; PosStrA <= (StrA.length() - lngLen + 1); ++PosStrA){ StrTempA = StrA.mid(PosStrA, lngLen); PosStrB = 1; for (PosStrB = 1; PosStrB <= (StrB.length() - lngLen + 1); ++PosStrB){ StrTempB = StrB.mid(PosStrB, lngLen); if (StrTempA == StrTempB){ TempRet.lngCountLike++; break; } } TempRet.lngSubRows++; } return TempRet; }
int IndistinctMatching(QString InputMatching, QString InputStandart, int MaxMatching = 4) { QString strInputMatching = InputMatching.toLower(); QString strInputStandart = InputStandart.toLower(); retCount gret; gret.lngCountLike = 0; gret.lngSubRows = 0; retCount tret; tret.lngCountLike = 0; tret.lngSubRows = 0; int lngCurLen = 0; //текущая длина подстроки //если не передан какой-либо параметр, то выход if ((MaxMatching == 0) || (strInputMatching.length() == 0) || (strInputStandart.length() == 0)){ return 0; }
// Цикл прохода по длине сравниваемой фразы for (lngCurLen = 1; lngCurLen <= MaxMatching; ++lngCurLen){ //Сравниваем строку A со строкой B tret = Matching(strInputMatching, strInputStandart, lngCurLen); gret.lngCountLike = gret.lngCountLike + tret.lngCountLike; gret.lngSubRows = gret.lngSubRows + tret.lngSubRows; //Сравниваем строку B со строкой A tret = Matching(strInputStandart, strInputMatching, lngCurLen); gret.lngCountLike = gret.lngCountLike + tret.lngCountLike; gret.lngSubRows = gret.lngSubRows + tret.lngSubRows; }
if (gret.lngSubRows == 0){ return 0; } float rez = ((float)gret.lngCountLike/(float)gret.lngSubRows); rez = rez*100; return (int)rez; }
Название: Re: Нечеткое сравнение строк
Отправлено: Vitto74 от Февраль 20, 2010, 13:22
Я смотрел в сторону морфологического разбора, но не хочу привязывать программу к русскому языку. Это будет универсальная оболочка для электронных учебников.
Название: Re: Нечеткое сравнение строк
Отправлено: BlackTass от Февраль 21, 2010, 19:40
Я смотрел в сторону морфологического разбора, но не хочу привязывать программу к русскому языку. Это будет универсальная оболочка для электронных учебников.
что мешает задавать параметры морфо-разбора через некие конфиги (то есть чтобы подключить язык нужно будет просто переписать настройки разбора на нужные) ? Проблемы (и то решаемые) будут только с иероглифической группой языков (кстати в вашем алгоритме также будут проблемы) и с полисинтетической группой. Корневые, флективные и агглютинирующие в принципе (с небольшими погрешностями) можно объединить в один разбор, но с разными параметрами.
Название: Re: Нечеткое сравнение строк
Отправлено: Vitto74 от Февраль 21, 2010, 22:26
Вы в чем-то правы, но эта функция уже работает и работает отлично, без единого сбоя. Морфологический разбор я, возможно, добавлю в будущих версиях.
|