unit MedProcLib;
   // для медучреждений
interface

uses SysUtils, SVAProcLib;

function ControlDs(d:string):boolean;
function CorrDs(var s:string):boolean;
procedure DivFIO(FIO:string; var F,I,O:string);
function Control_FIO(var s:string):boolean;
function ControlFIO(var s:string; Style:byte; Digit:boolean):boolean;
function OtToPol(s:string):string;
function ControlSNILS(var s:string):boolean;
function CheckSNILS(s:string):boolean;
function FullControlSNILS(s:string):boolean;
function ControlINN(s:string):boolean;

implementation

   { ----- Контроль (строгий) кода диагноза ----- }

function ControlDs(d:string):boolean;
var j:integer;
begin
  Result:= false;
  if d = '' then exit;
  if not (d[1] in ['A'..'Z']) then exit;
  j:= 2;
  if d[2] = ' ' then j:= 3; // отс. нач-ся 1-я пара цифр
  try
    StrToInt(Copy(d,j,2));  // 1-я пара цифр
  except
    exit
  end;
  if length(d) = j+1 then begin
    Result:= true; exit
  end;
  if d[j+2] <> '.' then exit;
  inc(j,3);
  if length(d) < j then begin
    Result:= true; exit
  end;
  try
    StrToInt(Copy(d, j, length(d)+1-j));  // второе число
    Result:= true;
  except
  end;
end;

   { --- Контроль и авто-корректировка КОДА ДИАГНОЗА --- }

function CorrDs(var s:string):boolean;
var d: string[7];
begin
  Result:= false;  // автокорректировке не поддается
  if s = '' then exit;
  d:= AnsiUpperCase(s);
  if not (d[1] in ['A'..'Z','А','В','Е','К','М','Н','О','Р','С','Т','У','Х'])
    then exit;  { - совсем некорректные буквы }
  if not(d[1] in ['A'..'Z']) then
    { рус --> lat }
    case  d[1] of
      'А': d[1]:='A';
      'В': d[1]:='B';
      'Е': d[1]:='E';
      'К': d[1]:='K';
      'М': d[1]:='M';
      'Н': d[1]:='H';
      'О': d[1]:='O';
      'Р': d[1]:='P';
      'С': d[1]:='C';
      'Т': d[1]:='T';
      'У': d[1]:='Y';
      'Х': d[1]:='X';
    end;
  s[1]:= d[1];  { - с буквой разобрались }
  if length(s) = 1 then exit;
  if s[2] = ' ' then
    delete(s,2,1);  { - убрали необязательный пробел }
  if length(s) = 2 then insert('0',s,2);
  if not ControlNumber(Copy(s,2,2), 2) then exit;
  if length(s)= 3 then begin
    Result:= true;
    exit;  { A99 }
  end;
  if s[4] <> '.' then
    if (s[4] in ['0'..'9']) then exit
    else s[4]:= '.';
  if length(s) = 4 then begin
    SetLength(s,3);
    Result:= true;
    exit { A99.-> A99 - точку удаляем ! }
  end;
  if length(s) > 6 then exit;
  if length(s) > 4 then
    if not ControlNumber(Copy(s,5,2), 0) then exit;
  Result:= true  // автокорректировка удалась
end; { CorrDs }

   { ------ Извлечение Ф. И. О. из строки FIO ------ }
   // для простого случая - когда фамилия (имя) без пробелов внутри
procedure DivFIO(FIO:string; var F,I,O:string);
var s: string; k,p: integer;
begin
  F:= ''; I:= ''; O:= '';
  s:= Trim(FIO);
  Del2Space(s);
    // поверим, чтобы после точки был пробел (или вставим его)
  k:= pos('.', s);
  while (k > 0) and (k < length(s)) do begin
    p:= k+1;
    if not(s[p] in [' ', '-']) then insert(' ', s, p);
    k:= Find('.', s, p);
  end;
  k:= pos(' ', s);
  if k > 0 then begin
    F:= Copy(s, 1, k-1);
    delete(s,1,k);
    k:= pos(' ', s);
    if k > 0 then begin
      I:= Copy(s, 1, k-1);
      delete(s,1,k);
      O:= s
    end
    else I:= s;
  end
  else F:= s
end;

   { ---- Ищем 1-й из 3-х символов в строке ---- }

function Pos3(c1,c2,c3:char; s:string; var c:char):integer; // local
var k1, k2, k3: integer;
begin
  Result:= 0;
  k1:= pos(c1, s);
  k2:= pos(c2, s);
  k3:= pos(c3, s);
  if (k1 = 0) and (k2 = 0) and (k3 = 0) then exit;
  if (k1 > 0) and (k2 = 0) and (k3 = 0) then Result:= k1
  else if (k1 = 0) and (k2 > 0) and (k3 = 0) then Result:= k2
  else if (k1 = 0) and (k2 = 0) and (k3 > 0) then Result:= k3
  else if k1 = 0 then Result:= Min2(k2, k3)
  else if k2 = 0 then Result:= Min2(k1, k3)
  else if k3 = 0 then Result:= Min2(k1, k2)
  else Result:= Min2(Min2(k1,k2), k3);
  if Result = k1 then c:= c1
  else if Result = k2 then c:= c2
  else if Result = k3 then c:= c3
end;

   { ---- Ищем 1-й из 2-х символов в строке ---- }

function Pos2(c1,c2:char; s:string; var c:char):integer; // local
var k1, k2: integer;
begin
  Result:= 0;
  k1:= pos(c1, s);
  k2:= pos(c2, s);
  if (k1 = 0) and (k2 = 0) then exit;
  if (k1 > 0) and (k2 = 0) then Result:= k1
  else if (k1 = 0) and (k2 > 0) then Result:= k2
  else Result:= Min2(k1, k2);
  if Result = k1 then c:= c1
  else if Result = k2 then c:= c2
end;

     { =======  Контроль Ф.И.О.  ======== }

function Control_FIO(var s:string):boolean;
 // допускаются внутри "-" и " " (пробел)
var
  ff,f,st: string; k: integer; c: char;

  function f1(var f:string):boolean; // одиночное имя
  var
    i: integer; a: string;
  begin
    if f = '' then begin
      Result:= true;  exit
    end;
    Result:= false;
    a:= AnsiUpperCase(f);
    for i:= 1 to length(a) do
      if not(a[i] in ['А'..'Я','Ё']) then exit;
    f:= AnsiLowerCase(f);
    f[1]:= a[1];
    if f[1] = ' ' then f[2]:= a[2];
    Result:= true;
  end;

begin { ControlFIO }

  Result:= false;
  s:= Trim(s);
  if s = '' then begin
    Result:= true; exit;  // пустое не проверяем
  end;
  Del2Space(s);
  Del2Minus(s);
     // ' - ', '- ', ' -'  => '-'
  while pos(' -', s) > 0 do delete(s, pos(' -',s), 1);
  while pos('- ', s) > 0 do delete(s, pos('- ',s) + 1, 1);
  f:= s;  // рабочая (изменяемая часть)
  ff:= '';  // готовая часть (в конце ff => s )
  k:= pos2('-', ' ', f, c);
  try
    while k > 0 do begin
      st:= Copy(f, 1, k-1);
      if not f1(st) then exit; // часть имени до "-"
      if ff = '' then ff:= st + c  // это первая часть имени
      else ff:= ff + st + c;
      delete(f,1,k);      // удаляем проверенную часть
      k:= pos2('-', ' ', f, c);
    end;
    if not f1(f) then exit;
    if ff = '' then ff:= f  // было одиночное имя
    else ff:= ff + f;
    k:= pos('-Оглы', ff);  if k > 0 then ff[k+1]:='о';
    k:= pos('-Кызы', ff);  if k > 0 then ff[k+1]:='к';
  except
    exit;
  end;
  s:= ff;
  Result:=true
end;

     { -------  Контроль Ф.И.О.  -------- }

        // к "-" добавлено ".", " ", "'"
function ControlFIO(var s:string; Style:byte; Digit:boolean):boolean;
  // Style: 0 - удобные (Фам Имя Отч), 1 - Прописные, 2 - Не изменять
  // если Digit=true - разрешается использовать цифры
var ff,f,st: string; k: integer; c:char;

  function f1(var f:string):boolean; // одиночное имя
  var
    i: integer; a,b: string;
    GoodChar: set of char;
  begin
    if f = '' then begin
      Result:= true;  exit
    end;
    Result:= false;
    b:= f;
    a:= AnsiUpperCase(f);
    GoodChar:= [#39,'А'..'Я','Ё'];
    if Digit then GoodChar:= GoodChar + ['0'..'9'];
    for i:= 1 to length(a) do
      if not(a[i] in GoodChar) then exit;
    Result:= true;
    if Style = 2 then exit;  // ничего не измен. - только провер.
    if Style = 1 then begin
      f:= a; exit   // все буквы прописные
    end;
    f:= AnsiLowerCase(f);
    f[1]:= a[1];
    if f[1] = ' ' then f[2]:= a[2];
    i:= pos(#39, a);
    if (i > 0) and (i < length(f)) then begin
      if f[i+1] <> #39 then f[i+1]:= b[i+1]
      else if i+2 <= length(f) then f[i+2]:= b[i+2];
    end;
    if i > 1 then f[i-1]:= b[i-1];
    Result:= true;
  end;

begin
  Result:= false;
  s:= Trim(s);
  if s = '' then begin
    Result:= true; exit;  // пустое не проверяем
  end;
  Del2Space(s);
  Del2Minus(s);
     // ' - ', '- ', ' -'  => '-'
  while pos(' -', s) > 0 do delete(s, pos(' -',s), 1);
  while pos('- ', s) > 0 do delete(s, pos('- ',s) + 1, 1);
  while pos(' .', s) > 0 do delete(s, pos(' .',s), 1);
  k:= pos(' '' ', s);   // O ' Hen => O'Hen
  while k > 0 do begin
    delete(s, k, 1);
    delete(s, k+1, 1);
    k:= pos(' '' ', s);
  end;
  f:= s;  // рабочая (изменяемая часть)
  ff:= '';  // готовая часть (в конце ff => s )
  if Digit then k:= pos3('-', '.', ' ', f, c)  // там где цифры, там и точка
  else k:= pos2('-', ' ', f, c);
  try
    while k > 0 do begin
      st:= Copy(f, 1, k-1);
      if not f1(st) then exit; // часть имени до "-"
      if ff = '' then ff:= st + c  // это первая часть имени
      else ff:= ff + st + c;
      delete(f,1,k);      // удаляем проверенную часть
      if Digit then k:= pos3('-', '.', ' ', f, c)
      else k:= pos2('-', ' ', f, c);
    end;
    if not f1(f) then exit;
    if ff = '' then ff:= f  // было одиночное имя
    else ff:= ff + f;
    if Style = 0 then begin
      k:= pos('-Оглы', ff);  if k > 0 then ff[k+1]:='о';
      k:= pos('-Кызы', ff);  if k > 0 then ff[k+1]:='к';
    end;
  except
    exit;
  end;
  s:= ff;
  Result:=true
end;

   { --- По отчеству определить пол --- }

function OtToPol(s:string):string;
var so: string;
begin
  Result:= '';
  if length(s) < 3 then exit;
  so:= Copy(s, length(s)-1, 2);
  if (so = 'ич') or (so = 'лы') then Result:='М'
  else begin
    so:= Copy(s, length(s)-2, 3);
    if (so = 'вна') or (so = 'чна') or (so = 'ызы') then Result:='Ж';
  end
end;

     { =======  Контроль формата СНИЛСа  ======== }

function ControlSNILS(var s:string):boolean;
var i:integer;
begin
  Result:= false;
  if length(s) <> 14 then exit;
  for i:= 1 to 14 do
    case i of
        4,8: if s[i] in ['0'..'9'] then exit
             else s[i]:= '-';
         12: if s[i] in ['0'..'9'] then exit
             else s[i]:= ' ';
       else  if not(s[i] in ['0'..'9']) then exit;
    end; { case }
  Result:= true;
end;

     { =======  Контроль кода СНИЛСа  ======== }
               { после ControlSNILS }
function CheckSNILS(s:string):boolean;
var i,sum:integer; sNum: string;
begin
  sNum:= Copy(s,1,11); Delete(sNum,8,1); Delete(sNum,4,1);
  sum:= 0;
  for i:= 1 to 9 do
    sum:= sum + (ord(sNum[i]) - 48) * (10 - i);
  Result:= (sum mod 101) mod 100 = StrToInt(Copy(s,13,2));
end;

     { =======  Полный контроль СНИЛСа  ======== }

function FullControlSNILS(s:string):boolean;
begin
  Result:= false;
  if ControlSNILS(s) then
    Result:= CheckSNILS(s)
end;

     { =======  Контроль ИНН  ======== }

function ControlINN(s:string):boolean;
begin
  if not(length(s) in [10,12]) then Result:=false
  else Result:= ControlNumber(s, length(s))
end;

end.
Hosted by uCoz