Sources
Delphi Russian Knowledge Base
DRKB - это самая большая и удобная в использовании база знаний по Дельфи в рунете, составленная Виталием Невзоровым

Функция приблизительного (нечеткого) сравнения строк

01.01.2007

Автор: Дмитрий Кузан

Недавно в поисках информации по интеллектуальным алгоритмам сравнения я нашел такой алгоритм — алгоритм сравнения (совпадения) двух строк, Так как он был написан на VBA, я под свои нужды переписал его на Delphi

Уважаемые пользователи проекта DelphiWorld, я думаю данная функция пригодится тем, кто часто пишет функции поиска, особенно когда поиск приблизителен. То есть, например, в БД забито "Иванав Иван" - с ошибкой при наборе, а ищется "Иванов". Так вот, данный алгоритм может вам найти "Иванав" при вводе "Иванов",а также при "Иван Иванов" - даже наоборот с определенной степенью релевантности при сравнении. А используя сравнение в процентном отношении, вы можете производить поиск по неточным данным с более-менее степенью похожести.

Еще раз повторяю, алгоритм не мой, я только его портировал на Delphi.

А метод был предложен Владимиром Кива, за что ему огромное спасибо.

//Функция нечеткого сравнения строк БЕЗ УЧЕТА РЕГИСТРА 
//------------------------------------------------------------------------------
//MaxMatching - максимальная длина подстроки (достаточно 3-4)
//strInputMatching - сравниваемая строка
//strInputStandart - строка-образец
 
// Сравнивание без учета регистра
// if IndistinctMatching(4, "поисковая строка", "оригинальная строка  - эталон") > 40 then ...
type
 
TRetCount = packed record
    lngSubRows
: Word;
    lngCountLike
: Word;
 
end;
 
//------------------------------------------------------------------------------
 
function Matching(StrInputA: WideString;
 
StrInputB: WideString;
  lngLen
: Integer): TRetCount;
var
 
TempRet: TRetCount;
 
PosStrB: Integer;
 
PosStrA: Integer;
 
StrA: WideString;
 
StrB: WideString;
 
StrTempA: WideString;
 
StrTempB: WideString;
begin
 
StrA := string(StrInputA);
 
StrB := string(StrInputB);
 
 
for PosStrA := 1 to Length(strA) - lngLen + 1 do
 
begin
   
StrTempA := System.Copy(strA, PosStrA, lngLen);
 
   
PosStrB := 1;
   
for PosStrB := 1 to Length(strB) - lngLen + 1 do
   
begin
     
StrTempB := System.Copy(strB, PosStrB, lngLen);
     
if SysUtils.AnsiCompareText(StrTempA, StrTempB) = 0 then
     
begin
       
Inc(TempRet.lngCountLike);
       
break;
     
end;
   
end;
 
   
Inc(TempRet.lngSubRows);
 
end; // PosStrA
 
 
Matching.lngCountLike := TempRet.lngCountLike;
 
Matching.lngSubRows := TempRet.lngSubRows;
end; { function }
 
//------------------------------------------------------------------------------
 
function IndistinctMatching(MaxMatching: Integer;
  strInputMatching
: WideString;
  strInputStandart
: WideString): Integer;
var
  gret
: TRetCount;
  tret
: TRetCount;
  lngCurLen
: Integer; //текущая длина подстроки
begin
   
//если не передан какой-либо параметр, то выход
 
if (MaxMatching = 0) or (Length(strInputMatching) = 0) or
   
(Length(strInputStandart) = 0) then
 
begin
   
IndistinctMatching := 0;
   
exit;
 
end;
 
  gret
.lngCountLike := 0;
  gret
.lngSubRows := 0;
   
// Цикл прохода по длине сравниваемой фразы
 
for lngCurLen := 1 to MaxMatching do
 
begin
       
//Сравниваем строку 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;
 
end;
 
 
if gret.lngSubRows = 0 then
 
begin
   
IndistinctMatching := 0;
   
exit;
 
end;
 
 
IndistinctMatching := Trunc((gret.lngCountLike / gret.lngSubRows) * 100);
end;

https://delphiworld.narod.ru/

DelphiWorld 6.0

 

 


uses
   
Math;
 
 
function DoStringMatch(s1, s2: string): Double;
 
var
   i
, iMin, iMax, iSameCount: Integer;
 
begin
   iMax
:= Max(Length(s1), Length(s2));
   iMin
:= Min(Length(s1), Length(s2));
   iSameCount
:= -1;
   
for i := 0 to iMax do
   
begin
     
if i > iMin then
       
break;
     
if s1[i] = s2[i] then
       
Inc(iSameCount)
     
else
       
break;
   
end;
   
if iSameCount > 0 then
     
Result := (iSameCount / iMax) * 100
   
else
     
Result := 0.00;
 
end;
 
 procedure TForm1
.Button1Click(Sender: TObject);
 
var
   match
: Double;
 
begin
   match
:= DoStringMatch('SwissDelphiCenter', 'SwissDelphiCenter.ch');
   
ShowMessage(FloatToStr(match) + ' % match.');
   
// Resultat: 85%
 
// Result  : 85%
end;

Взято с сайта: https://www.swissdelphicenter.ch