Advertisement
Doomer3D

COMPARE_STRINGS

Mar 14th, 2017
123
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. --drop function meta_form_map.COMPARE_STRINGS(text, text, boolean, boolean);
  2.  
  3. -- определить степень похожести строк
  4. CREATE OR REPLACE FUNCTION meta_form_map.COMPARE_STRINGS
  5.   (
  6.     S1 text,                                    -- первая строка
  7.     S2 text,                                    -- вторая строка
  8.     IGNORE_CASE boolean = FALSE,                -- игнорировать регистр
  9.     RELATIVE_LENGTH boolean = FALSE             -- если задано, возвращает относительную разницу строк
  10.   )
  11.   RETURNS real LANGUAGE plpgsql
  12. AS $FUNCTION$
  13. declare
  14.     valueOfReplace real = 1.0;                  -- цена замены символа строки
  15.     valueOfDelete  real = 1.0;                  -- цена удаления символа строки
  16.     valueOfInsert  real = 1.0;                  -- цена вставки символа строки
  17.     L1 integer;                                 -- длина первой строки
  18.     L2 integer;                                 -- длина второй строки
  19.     C1 integer;
  20.     C2 integer;
  21.     DIFFERENCE real;
  22.     D real[][];
  23. BEGIN
  24.     IF IGNORE_CASE THEN
  25.       -- игнорируем регистр
  26.       S1 := upper(S1);
  27.       S2 := upper(S2);
  28.     END IF;
  29.    
  30.     -- длины строк
  31.     L1 := length(S1);
  32.     L2 := length(S2);
  33.    
  34.     -- создаем массив
  35.     D := array_fill(0, array[L1 + 1, L2 + 1]);
  36.    
  37.     -- начальная инициализация
  38.     FOR i IN 1..L1 + 1 LOOP
  39.        D[i][1] := (i - 1)::real;
  40.     END LOOP;
  41.     FOR j IN 1..L2 + 1 LOOP
  42.        D[1][j] := (j - 1)::real;
  43.     END LOOP;
  44.    
  45.     -- главный цикл
  46.     FOR i IN 2..L1 + 1 LOOP
  47.         FOR j IN 2..L2 + 1 LOOP
  48.             -- если символы совпадают то ничего делать не надо
  49.             C1 := ascii(substring(S1 from i - 1 for 1));
  50.             C2 := ascii(substring(S2 from j - 1 for 1));
  51.             DIFFERENCE := case when C1 = C2 then 0 else 1 end::real;
  52.            
  53.             D[i][j] := least
  54.             (
  55.                 D[i - 1][j] + valueOfDelete,
  56.                 D[i][j - 1] + valueOfInsert,
  57.                 D[i - 1][j - 1] + valueOfReplace * DIFFERENCE
  58.             );
  59.         END LOOP;
  60.     END LOOP;
  61.    
  62.     -- отладочный вывод
  63.     --RAISE NOTICE 'D: %', D;
  64.    
  65.     IF RELATIVE_LENGTH THEN
  66.         RETURN D[L1 + 1][L2 + 1] / greatest(L1, L2)::real;
  67.     ELSE
  68.         RETURN D[L1 + 1][L2 + 1];
  69.     END IF;
  70. END;
  71. $FUNCTION$
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement