국비교육/국비교육 복습

day15_regex_Test04 : 정규 표현식 + 윤년 판정 (★★)

Luver Duck 2022. 8. 15. 20:51

(Q) 날짜 형식 검사

1) 사용자에게 생년월일을 YYYY-MM-DD 형식으로 입력받아 올바른 날짜 형식인지 검사하세요

- 연도는 1900년부터 2099년까지 가능합니다

- 최초 검사식을 만들 때는 모든 달은 31일까지 있다고 가정하고 만듭니다

 

2) 큰달(31일)과 작은달(30일)을 구분해서 만듭니다(2월은 28일로 가정)

3) 윤년을 고려하도록 만듭니다(정규표현식만으로 불가능합니다)

 

1) 모든 달을 31일까지 있다고 가정

- 정규 표현식 시각화

- 메인 메소드

package day15_regex;

import java.util.Scanner;
import java.util.regex.Pattern;

public class Test04 {

	public static void main(String[] args) {
		
		Scanner sc = new Scanner(System.in);
		
		// 생년월일의 정규 표현식
		String regex = "^(19[0-9]{2}|20[0-9]{2})-(0[1-9]|1[0-2])-(0[1-9]|1[0-9]|2[0-9]|3[01])$";
		
		// 생년월일 입력
		System.out.print("생년월일 : ");
		String birth = sc.next();
		
		// 판정
		boolean check = Pattern.matches(regex, birth);
		
		// 출력
		System.out.println("결과 : " + check);
		
		sc.close();
	}
}

 

 

2) 큰 달(31일), 작은 달(30일), 2월(28일)로 구분

- 정규 표현식 시각화

- 메인 메소드

package day15_regex;

import java.util.Scanner;
import java.util.regex.Pattern;

public class Test04_1 {

	public static void main(String[] args) {
		
		// 생년월일 입력
		Scanner sc = new Scanner(System.in);
		System.out.print("생년월일 : ");
		String birth = sc.next();
		sc.close();
		
		// 생년월일의 정규 표현식
		// 큰 달(31일까지 있는 달), 작은 달(30일까지 있는 달), 2월(28일까지 있는 달)로 구분
		String regex = "^(19[0-9]{2}|20[0-9]{2})-((0[13578]|1[02])-(0[1-9]|1[0-9]|2[0-9]|3[01])|(0[469]|11)-(0[1-9]|1[0-9]|2[0-9]|30)|02-(0[1-9]|1[0-9]|2[0-8]))$";
		
		// 판정
		boolean check = Pattern.matches(regex, birth);
		
		// 출력
		System.out.println("결과 : " + check);
	}
}

 

 

** 2)를 switch ~ case로 작성한 경우

- 생년월일에서 월에 해당하는 값을 추출해서 switch 각 case의 String 값과 비교

package day15_regex;

import java.util.Scanner;
import java.util.regex.Pattern;

public class Test04_etc {

	public static void main(String[] args) {

		// 생년월일 입력
		Scanner sc = new Scanner(System.in);
		System.out.print("생년월일 : ");
		String birth = sc.next();
		sc.close();
		
		// 생년월일의 정규 표현식
		String regex = null;
		switch(birth.substring(5, 7)) {
		case "02":
			regex = "^(19[0-9]{2}|20[0-9]{2})-(02)-(0[1-9]|1[0-9]|2[0-8])$";
			break;
		case "04": case "06": case "09": case "11":
			regex = "^(19[0-9]{2}|20[0-9]{2})-(0[469]|11)-(0[1-9]|1[0-9]|2[0-9]|30)$";
			break;
		case "01": case "03": case "05": case "07": case "08": case "10": case "12":
			regex = "^(19[0-9]{2}|20[0-9]{2})-(0[13578]|1[02])-(0[1-9]|1[0-9]|2[0-9]|3[01])$";
			break;
		}
		
		// 판정
		boolean check = Pattern.matches(regex, birth);

		// 출력
		System.out.println("결과 : " + check);
	}
}

 

3) 2)에서 윤년을 고려하는 경우

- 정규 표현식 시각화

i) 윤년인 경우 (2월이 29일까지 존재)

 

ii) 윤년이 아닌 경우 (2월이 28일까지 존재)

- 메인 메소드

package day15_regex;

import java.util.Scanner;
import java.util.regex.Pattern;

public class Test04_2 {

	public static void main(String[] args) {
		
		// 생년월일 입력
		Scanner sc = new Scanner(System.in);
		System.out.print("생년월일 : ");
		String birth = sc.next();
		sc.close();
		
		// 생년월일의 정규 표현식 - 윤년을 고려하는 경우
		// 입력에서 년도만 추출 : (birth.substring(0, 4)
		// 추출한 년도를 숫자로 변환 : Integer.parseInt(birth.substring(0, 4))
		int yearValue = Integer.parseInt(birth.substring(0, 4));	
		
		// 윤년 판정
		// 년도가 4의 배수이면 윤년 O
		// 년도가 4의 배수이면서 100의 배수이면 윤년 X
		// -> 년도가 4의 배수이면서(&&) 100의 배수가 아니면 윤년 O
		// 년도가 4의 배수이면서 100의 배수이지만 400의 배수이면(||) 윤년 O
		boolean leap = yearValue % 4 == 0 && yearValue % 100 != 0 || yearValue % 400 == 0;
		
		// 윤년일 때와 윤년이 아닐 때의 정규 표현식
		String regex;
		if(leap) {
			regex = "^(19[0-9]{2}|20[0-9]{2})-((0[13578]|1[02])-(0[1-9]|1[0-9]|2[0-9]|3[01])|(0[469]|11)-(0[1-9]|1[0-9]|2[0-9]|30)|02-(0[1-9]|1[0-9]|2[0-9]))$";
		}
		else {
			regex = "^(19[0-9]{2}|20[0-9]{2})-((0[13578]|1[02])-(0[1-9]|1[0-9]|2[0-9]|3[01])|(0[469]|11)-(0[1-9]|1[0-9]|2[0-9]|30)|02-(0[1-9]|1[0-9]|2[0-8]))$";
		}
		
		// 판정
		boolean check = Pattern.matches(regex, birth);
		
		// 출력
		System.out.println("결과 : " + check);
	}
}

 

- 윤년 판정
  1) 년도가 4의 배수이면 윤년 O
  2) 년도가 4의 배수이면서 100의 배수이면 윤년 X
       -> 년도가 4의 배수이면서(&&) 100의 배수가 아니면 윤년 O
  3) 년도가 4의 배수이면서 100의 배수이지만 400의 배수이면(||) 윤년 O