1. 목적
[인수 조건]
Given
개발자는 주민등록번호 유효성 검증을 위한 정규식을 이용한다.
코드가 길어질 경우 라이브러리 React-hook-form을 사용할 수 있다.
text input 2개로 구성된 컴포넌트로 구현한다.
When
주민등록번호 컴포넌트 GUI와 유효성 검증하는 함수로 각각 분리한다.
Then
1. 00년생 이전/이후와 생년월일, 성별 케이스별로 나누어
주민등록번호의 뒷 번호 첫 번째 자리까지 유효성 검증을 진행한다.
2. 실시간으로 유효성 검증이 진행된다.
3. 올바르지 않은 주민번호 입력시 가이드 텍스트가 표시된다.
[설명]
보상 안내 받는 이와 예금주의 주민등록번호를 받았을 때 실시간 유효성 검증 기능이 있는 주민등록번호 컴포넌트를 구현한다.
- 케이스는 00년생 이전과 이후로 나뉘며
- 앞, 뒷 번호 자릿수
- 생년월일 범위에 속하는지
- 뒷 번호가 체계에 맞게 구성되어 있는지 검증.
- 앞자리 6자리가 모두 채워졌을 경우, 다음 텍스트박스로 커서를 이동한다.
[참고]
- 주민번호 검증 가능해야함
- 검증은 02년생 이전과 이후로 나뉨
- 앞자리 뒷자리 모두 검증 가능해야함.
- 디자인 제외 text input 2개로 구성된 컴포넌트
- 올바르지 않은 주민번호 입력시 가이드 텍스트 표시되어야함 (옵션)
- 실시간 유효성 검증 기능
2. 주민등록번호 체계
앞자리
- 연도
- 월
- 일
뒷자리
- 성별 (dash가 없을 경우 7번째 자리)
- 이후 번호들은 아래 전체적인 주민번호 계산 방법 참고
3. 필요한 기능
기본 조건
- 숫자 이외의 값을 넣을 수 없다. (입력값 정수 체크)
- 앞자리는 6자리를 넘을 수 없고, 뒷자리는 7자리를 넘을 수 없다.
- 앞자리는 6자리여야 하고, 뒷자리는 7자리여야 한다.
- 크기만큼 입력됐다면 다음 필드로 포커스가 이동해야 한다.
- 앞자리가 빈칸일 경우 뒷자리 텍스트박스를 입력할 수 없다.
- 두 텍스트박스가 공백일 경우 필수 항목이라는 표시를 해야 한다.
앞자리
- 정규식 - 대시 없는 경우
- const regex = /^\d{2}(0[1-9]|1[0-2])(0[1-9]|[1-2][0-9]|3[0-1])\d{7}$/
- ^: 문자열의 시작
- \d: 숫자
- {2}: 바로 앞의 표현식이 두 번 반복되어야 함. 여기서는 /d{2} 니까 두자리 숫자
- (0[1-9]|1[0-2]): 01~09 또는 10~12의 두 자리 숫자
- (0[1-9]|[1-2][0-9]|3[0-1]): 01~09 또는 10~29 또는 30, 31 중 하나의 두 자리 숫자
- [-] : 대시가 포함되어야 함.
- \d{7}: 7자리 숫자
- $: 문자열의 끝
- const regex = /^\d{2}(0[1-9]|1[0-2])(0[1-9]|[1-2][0-9]|3[0-1])\d{7}$/
- 2월일 경우 28일까지여서 추가 처리가 필요할 것 같다.
뒷자리
- 전체적인 체크로직 검증
- 주민등록번호의 앞 6자리의 수에 처음부터 차례대로 2,3,4,5,6,7 을 곱한다.
- 그 다음, 뒤 7자리의 수에 마지막 자리만 제외하고 차례대로 8,9,2,3,4,5 를 곱한다.
- 이렇게 곱한 각 자리의 수들을 모두 더한다.
- 모두 더한 수를 11로 나눈 나머지를 구한다.
- 이 나머지를 11에서 뺀다.
- 이렇게 뺀 수가 두 자릿수이면, 즉 10보다 크면 다시 11로 나누어 나머지 값을 구한다.
- 이렇게 해서 나온 최종 값을 주민등록번호의 마지막 자리 수와 비교해서 같으면 유효한 번호이고 다르면 잘못된 값이다.
- 성별 검증
- 성별부분이 1 ~ 4 가 아닌 경우
-
// 연도 계산 - 1 또는 2: 1900년대, 3 또는 4: 2000년대 cc = (genda == "1" || genda == "2") ? "19" : "20"; if (isValidDate(cc+yy+mm+dd) == false) { alert("주민등록번호 앞자리를 다시 입력하세요."); return false; }
- 1: 1900년대에 출생한 남자
- 2: 1900년대에 출생한 여자
- 3: 2000년대에 출생한 남자
- 4: 2000년대에 출생한 여자
- 5: 1900년대에 출생한 외국인 남자
- 6: 1900년대에 출생한 외국인 여자
- 7: 2000년대에 출생한 외국인 남자
- 8: 2000년대에 출생한 외국인 여자
전체 주민등록번호 유효성 체크
- https://yoonhihi.tistory.com/157
- https://blog.naver.com/PostView.nhn?blogId=javaking75&logNo=140191702532
- https://delirussum.tistory.com/81
4. 경우의 수
년월일성별전체
남성 | 1900년대 | 01, 03~12 | 02 | 01~31 | 01~30 | 28 | 1 | 통합 계산 |
2000년대 | 3 | |||||||
여성 | 1900년대 | 2 | ||||||
2000년대 | 4 |
+ 외국인도 있을 수 있다. (승림 과장님 확인)
5. 논리 흐름 예상
→ 컴포넌트 1개, useCheckKoreanID Hook 1개, 유효성 검증 Util 함수 1개
- 주민등록번호 input text 2개를 하나의 string으로 모아서 검증하는 함수 → 1900년대 / 2000년대 분간
- <KoreanIDCheck /> 컴포넌트
- text box 2개의 상태가 변경될 때마다 모든 숫자를 모아서 useEffect로 함수 호출
- props로 useCheckKoreanID에 전달
- KoreanIDCheckUtil에서 검증 결과 반환
- useCheckKoreanID 훅에서 가이드 텍스트로 상태 알려준다.
- props
- 주민등록번호 전체 string ➔
- 전체 유효 상태 체크 boolean ←
- 가이드 메시지 string ←
- text box 2개의 상태가 변경될 때마다 모든 숫자를 모아서 useEffect로 함수 호출
[Sequence Diagram]
- <RegNumber />
- Props
- setIsValid : 컴포넌트 바깥에서 상태 저장을 위한 validation 검증 여부
- setRegistrationNumber : 컴포넌트 바깥에서 상태 저장을 위한 validation 검증 여부
- Props
- useRegNumber
- Custom Hooks
- props를 유효성 검증 Util에 옮겨주는 역할
- 유효성 검증 부위에 따른 가이드 메시지 전달 역할
- Custom Hooks
- validRegNumberUtil
- 내부에 순수함수들 모음집 만들 예정…
- Util 함수
- 앞자리
- 숫자가 아닌 값을 입력한 경우
- 연월일(YYMMDD) 형식이 제대로 구성되어 있는가?
- 앞자리가 6자리가 아닌 경우
- 실제 달력에 있는 날짜인가 아닌가
- 뒷자리
- 한국인인가, 외국인인가?
- 숫자가 아닌 값을 입력한 경우
- 첫 번째 자리가 연도에 따라 성별이 정확히 입력되었는가?
- 1~4인가
- 1 또는 2: 1900년대, 3 또는 4: 2000년대인가?
- 전체적으로 유효한 주민번호가 맞는가
- ABCDEF - GHIJKLM
- 검증 공식: M = (11 - ((2×A + 3×B + 4×C + 5×D + 6×E + 7×F + 8×G + 9×H + 2×I + 3×J + 4×K + 5×L) % 11)) % 10
- 1~4인가
- 7자리가 아닌 경우
- 7자리일 경우 전체 주민등록번호가 유효한지 계산
- 앞자리
7. 구조
페이지에서 컴포넌트 호출 방법
<RegNumber
setIsValid={setIsValid}
setRegistrationNumber={setRegistrationNumber}
/>
컴포넌트 내부
export const RegNumber = (props: RegNumberProps) => {
const {
isValidFrontRegNumber,
isValidBackRegNumber,
frontRegNumber,
backRegNumber,
validRegNumberUtil,
} = useRegNumber();
useEffect(() => {
if (props.setIsValid) {
props.setIsValid(isValidFrontRegNumber && isValidBackRegNumber);
}
if (props.setRegistrationNumber) {
props.setRegistrationNumber(frontRegNumber + backRegNumber);
}
}, [
isValidFrontRegNumber,
isValidBackRegNumber,
frontRegNumber,
backRegNumber,
]);
Custom Hook
export const useRegNumber = () => {
const [isValidFrontRegNumber, setValidFrontRegNumber] =
useState<boolean>(false);
const [isValidBackRegNumber, setValidBackRegNumber] =
useState<boolean>(false);
const [frontRegNumber, setFrontRegNumber] = useState<string>("");
const [backRegNumber, setBackRegNumber] = useState<string>("");
const validRegNumberUtil = (
frontRegNumber: string,
backRegNumber: string
) => {
console.log("frontRegNumber : ", frontRegNumber);
console.log("backRegNumber : ", backRegNumber);
const regExpFront = /^[0-9]{6}$/;
const regExpBack = /^[1-9][0-9]{6}$/;
if (frontRegNumber || backRegNumber) {
const isValidFrontRegNumber = regExpFront.test(frontRegNumber);
const isValidBackRegNumber = regExpBack.test(backRegNumber);
setValidFrontRegNumber(isValidFrontRegNumber);
setValidBackRegNumber(isValidBackRegNumber);
setFrontRegNumber(frontRegNumber);
setBackRegNumber(backRegNumber);
}
};
공통 Utill
- 글자수 제한, 문자열, 영문 타입 등
8. 관련 정규식 및 라이브러리 확인
- 주민등록번호 관련 정규식
- 주민등록번호 전체 계산 검증 공식
- React-hook-form 라이브러리를 적용할 때와 적용하지 않을 때 장단점
'개발 > React.js' 카테고리의 다른 글
Dynamic Route - Slug (0) | 2024.09.13 |
---|---|
Xlsx parsing + react-table (0) | 2024.09.13 |
OAuth 인증 - 인가에 대하여 (0) | 2024.09.13 |
전역 상태 관리 라이브러리 - Zustand vs Recoil (0) | 2024.09.13 |
파일 Drag & Drop (0) | 2024.09.13 |