132 lines
3.3 KiB
Plaintext
132 lines
3.3 KiB
Plaintext
{*******************************************************}
|
|
{ }
|
|
{ Tocsg.Valid }
|
|
{ }
|
|
{ Copyright (C) 2025 kku }
|
|
{ }
|
|
{*******************************************************}
|
|
|
|
unit Tocsg.Valid;
|
|
|
|
interface
|
|
|
|
uses
|
|
System.SysUtils, Winapi.Windows;
|
|
|
|
function IsValidKoreanRegNo(sRegNo: String): Boolean;
|
|
|
|
implementation
|
|
|
|
uses
|
|
System.DateUtils, Tocsg.Exception;
|
|
|
|
const
|
|
// 주민번호, 외국인등록번호 검증 가중치
|
|
arrWeights: array[1..12] of Integer = (2, 3, 4, 5, 6, 7, 8, 9, 2, 3, 4, 5);
|
|
|
|
// 주민번호에서 생년월일 검증
|
|
function IsValidDateFromSSN(const SSN: string): Boolean;
|
|
var
|
|
nYear, nMonth, nDay, nFYear, n: Integer;
|
|
dtTemp: TDateTime;
|
|
begin
|
|
Result := false;
|
|
|
|
if Length(SSN) < 7 then
|
|
exit;
|
|
|
|
try
|
|
nYear := StrToIntDef(Copy(SSN, 1, 2), -1);
|
|
if nYear = -1 then exit;
|
|
nMonth := StrToIntDef(Copy(SSN, 3, 2), -1);
|
|
if nMonth = -1 then exit;
|
|
nDay := StrToIntDef(Copy(SSN, 5, 2), -1);
|
|
if nDay = -1 then exit;
|
|
n := StrToIntDef(SSN[7], -1);
|
|
if n = -1 then exit;
|
|
|
|
case n of
|
|
1, 2: nFYear := 1900 + nYear;
|
|
3, 4: nFYear := 2000 + nYear;
|
|
5, 6: nFYear := 1900 + nYear; // 외국인 등록번호 (2000년 이전)
|
|
7, 8: nFYear := 2000 + nYear; // 외국인 등록번호 (2000년 이후)
|
|
else exit;
|
|
end;
|
|
|
|
Result := TryEncodeDate(nFYear, nMonth, nDay, dtTemp);
|
|
except
|
|
on E: Exception do
|
|
ETgException.TraceException(E, 'Fail .. IsValidDateFromSSN()');
|
|
end;
|
|
end;
|
|
|
|
function IsValidForeignRegNo(sRegNo: String): Boolean;
|
|
var
|
|
i, nSum, nCheck, nLastDigit: Integer;
|
|
begin
|
|
Result := false;
|
|
|
|
if Length(sRegNo) < 13 then
|
|
exit;
|
|
|
|
// 외국인 등록번호는 7번째 자리가 5~8번이어야 함
|
|
if not (sRegNo[7] in ['5', '6', '7', '8']) then
|
|
exit;
|
|
|
|
// 가중치 계산
|
|
nSum := 0;
|
|
for i := 1 to 12 do
|
|
nSum := nSum + StrToInt(sRegNo[i]) * arrWeights[i];
|
|
|
|
// 검증 숫자 계산
|
|
nCheck := (11 - (nSum mod 11) + 2) mod 10;
|
|
nLastDigit := StrToInt(sRegNo[13]);
|
|
|
|
Result := nCheck = nLastDigit;
|
|
end;
|
|
|
|
// 주민번호 검증
|
|
// 외국인등록번호 검증 추가 25_0623 10:45:05 kku
|
|
// 2017년 이후 새로운 주민번호 방식(예: 지역번호 변경 등)에는 대응하지 않음
|
|
function IsValidKoreanRegNo(sRegNo: String): Boolean;
|
|
var
|
|
i, nSum, nCheck, nCalc: Integer;
|
|
begin
|
|
Result := false;
|
|
|
|
sRegNo := StringReplace(sRegNo, '-', '', [rfReplaceAll]);
|
|
|
|
// 생년월일 유효성 체크
|
|
if not IsValidDateFromSSN(sRegNo) then
|
|
exit;
|
|
|
|
// 13자리 숫자인지 확인
|
|
if Length(sRegNo) < 13 then
|
|
exit;
|
|
|
|
// 외국인 등록번호는 7번째 자리가 5~8번임
|
|
if sRegNo[7] in ['5', '6', '7', '8'] then
|
|
begin
|
|
Result := IsValidForeignRegNo(sRegNo);
|
|
exit;
|
|
end;
|
|
|
|
// 숫자만으로 이루어졌는지 확인
|
|
for i := 1 to 13 do
|
|
if not CharInSet(sRegNo[i], ['0'..'9']) then
|
|
exit;
|
|
|
|
// 가중치 계산
|
|
nSum := 0;
|
|
for i := 1 to 12 do
|
|
nSum := nSum + (Ord(sRegNo[i]) - Ord('0')) * arrWeights[i];
|
|
|
|
// 검증 숫자 계산
|
|
nCalc := (11 - (nSum mod 11)) mod 10;
|
|
nCheck := Ord(sRegNo[13]) - Ord('0');
|
|
|
|
Result := nCalc = nCheck;
|
|
end;
|
|
|
|
end.
|