IT•개발 끄적/Java

[JAVA] 정규식을 이용한 마스킹(정규표현식 마스킹 처리)

소다맛사탕 2021. 6. 30. 22:02
반응형

안녕하세요. 소다맛사탕 입니다.

지난 포스팅 '[java] 휴대폰 번호, 계좌번호, 이름 마스킹(masking)'의 버전2, 정규식을 이용한 마스킹을 알아보겠습니다.

 

※ 정규식(또는 정규표현식) ; 텍스트 데이터 중에서 원하는 조건과 일치하는 문자열을 찾아내기 위해 사용하는 것으로 미리 정의된 기호와 문자를 이용해서 작성한 문자열.

 

java.util.regex.Matcherjava.util.regex.Pattern 을 사용해 정규식을 이용하여 마스킹 처리를 작성해 보겠습니다.

 

1. 이름 마스킹

// 이름 가운데 글자 마스킹
public static String nameMasking(String name) throws Exception {
	// 한글만 (영어, 숫자 포함 이름은 제외)
	String regex = "(^[가-힣]+)$";
	
	Matcher matcher = Pattern.compile(regex).matcher(name);
	if(matcher.find()) {
		int length = name.length();
		
		String middleMask = "";
		if(length > 2) {
			middleMask = name.substring(1, length - 1);
		} else {	// 이름이 외자
			middleMask = name.substring(1, length);
		}
		
		String dot = "";
		for(int i = 0; i<middleMask.length(); i++) {
			dot += "*";
		}
		
		if(length > 2) {
			return name.substring(0, 1)
					+ middleMask.replace(middleMask, dot)
					+ name.substring(length-1, length);
		} else { // 이름이 외자 마스킹 리턴
			return name.substring(0, 1)
					+ middleMask.replace(middleMask, dot);
		}
	}
	return name;
}

이름 마스킹은 지난번 포스팅의 로직에서 한글 정규식 패턴만 가져올 수 있게 변경하였습니다.

마찬가지로 2글자 이상의 이름은 가운데 글자 마스킹. 외자는 끝자리만 마스킹.

 

2. 휴대폰번호 마스킹

// 휴대폰번호 마스킹(가운데 숫자 4자리 마스킹)
public static String phoneMasking(String phoneNo) throws Exception {
	String regex = "(\\d{2,3})-?(\\d{3,4})-?(\\d{4})$";
	
	Matcher matcher = Pattern.compile(regex).matcher(phoneNo);
	if(matcher.find()) {
		String target = matcher.group(2);
		int length = target.length();
		char[] c = new char[length];
		Arrays.fill(c, '*');
		
		return phoneNo.replace(target, String.valueOf(c));
	}
	return phoneNo;
}

휴대폰번호 마스킹가운데 숫자 4자리 마스킹이고, '-'(하이픈)이 들어오나 안들어오나, 숫자 길이와 형식이 맞으면 마스킹 처리가 됩니다.

 

3. 이메일 마스킹

// 이메일 마스킹(앞3자리 이후 '@'전까지 마스킹)
public static String emailMasking(String email) throws Exception {
	String regex = "\\b(\\s+)+@(\\s+.\\s+)";
	
	Matcher matcher = Pattern.compile(regex).matcher(email);
	if(matcher.find()) {
		String target = matcher.group(1);
		int length = target.length();
		if(length > 3) {
			char[] c = new char[length - 3];
			Arrays.fill(c, '*');
			
			return email.replace(target, target.substring(0, 3) + String.valueOf(c));
		}
	}
	return email;
}

이메일 마스킹앞3자리 제외, @전까지 마스킹 처리입니다. 이메일 형식이 올바르다면 마스킹 처리가 됩니다.

 


 

 

4. 계좌번호 마스킹

// 계좌번호 마스킹(뒤 5자리)
public static String accountNoMasking(String accountNo) throws Exception {
	// 계좌번호는 숫자만 파악하므로
    String regex = "(^[0-9]+)$";
	
	Matcher matcher = Pattern.compile(regex).matcher(accountNo);
	if(matcher.find()) {
		int length = accountNo.length();
		if(length > 5) {
			char[] c = new char[5];
			Arrays.fill(c, '*');
			
			return accountNo.replace(accountNo, accountNo.substring(0, length-5) + String.valueOf(c));
		}
	}
	return accountNo;
}

계좌번호 마스킹뒷 5자리 숫자를 마스킹 처리하고, 정규식 패턴에 상관없이 숫자 형식 패턴으로 이뤄져 있다면 상관없이 마스킹 처리가 됩니다.

계좌번호는 각 은행마다 자릿수가 다 틀려서 숫자 패턴만 이용했습니다.

 

5. 생년월일 마스킹

// 생년월일 마스킹(8자리)
public static String birthMasking(String birthday) throws Exception {
	String regex = "^((19|20)\\d\\d)?([-/.])?(0[1-9]|1[012])([-/.])?(0[1-9]|[12][0-9]|3[01])$";
	
	Matcher matcher = Pattern.compile(regex).matcher(birthday);
	if(matcher.find()) {
		return birthday.replace("[0-9]", "*");
	}
	return birthday;
}

생년월일 마스킹숫자 모두 마스킹 처리이고, '-'(하이픈), '.'(점)이 들어오나 안들어오나 생년월일 8자리 형식이 올바르다면 마스킹 처리 됩니다. 

 

6. 카드번호 마스킹

// 카드번호 가운데 8자리 마스킹
public static String cardMasking(String cardNo) throws Exception {
	// 카드번호 16자리 또는 15자리 '-'포함/미포함 상관없음
	String regex = "(\\d{4})-?(\\d{4})-?(\\d{4})-?(\\d{3,4})$";
	
	Matcher matcher = Pattern.compile(regex).matcher(cardNo);
	if(matcher.find()) {
		String target = matcher.group(2) + matcher.group(3);
		int length = target.length();
		char[] c = new char[length];
		Arrays.fill(c, '*');
		
		return cardNo.replace(target, String.valueOf(c));
	}
	return cardNo;
}

카드번호 마스킹가운데 8자리 숫자 마스킹 처리이고, 마찬가지로 '-'(하이픈)이 포함된 카드 번호 숫자 형식이 올바르다면 마스킹 처리가 됩니다.

 

7. 주소 마스킹

// 주소 마스킹(신주소, 구주소, 도로명 주소 숫자만 전부 마스킹)
public static String addressMasking(String address) throws Exception {
	// 신(구)주소, 도로명 주소
	String regex = "(([가-힣]+(\\d{1,5}|\\d{1,5}(,|.)\\d{1,5}|)+(읍|면|동|가|리))(^구|)((\\d{1,5}(~|-)\\d{1,5}|\\d{1,5})(가|리|)|))([ ](산(\\d{1,5}(~|-)\\d{1,5}|\\d{1,5}))|)|";
	String newRegx = "(([가-힣]|(\\d{1,5}(~|-)\\d{1,5})|\\d{1,5})+(로|길))";
	
	Matcher matcher = Pattern.compile(regex).matcher(address);
	Matcher newMatcher = Pattern.compile(newRegx).matcher(address);
	if(matcher.find()) {
		return address.replaceAll("[0-9]", "*");
	} else if(newMatcher.find()) {
		return address.replaceAll("[0-9]", "*");
	}
	return address;
}

위의 java 소스를 보시는것과 같이 주소는 정규식이 매우 험난합니다. 제가 이렇게까지 공들이진 못하구요. 우아한형제 기술노트에서 구주소, 신주소, 도로명 주소에 관련된 정규식이 있어 참조했습니다.

 

※ 참조(주소 마스킹 관련)

https://techblog.woowahan.com/2505/

 

정규식 관련 패턴이나 설명을 들고 다시 돌아오겠습니다.