웹 개발을 하다 보면 사용자가 입력한 값이 올바른 형식인지 검사해야 하는 경우가 매우 많습니다.
예를 들어 다음과 같은 상황입니다.
- 휴대폰 번호 형식 확인
- 이메일 주소 형식 확인
- 아이디 규칙 검사
- 비밀번호 정책 검사
- 날짜 형식 검사
이때 많이 사용하는 것이 정규표현식(Regular Expression, Regex) 입니다.
정규표현식은 문자열 패턴을 정의하여 특정 형식의 문자열인지 검사하는 방법입니다.
정규표현식 검증 함수 예제
실제로 사용하는 검증 함수를 만들어두면 다양한 입력값을 쉽게 검사할 수 있습니다.
function verify_code(str, type) {
let regExp = "";
switch (type) {
case "cell_phone": regExp = /^\d{3}-\d{3,4}-\d{4}$/; break;
case "telephone": regExp = /^\d{2,3}-\d{3,4}-\d{4}$/; break;
case "email": regExp = /^[0-9a-zA-Z]([-_\.]?[0-9a-zA-Z])*@[0-9a-zA-Z]([-_\.]?[0-9a-zA-Z])*\.[a-zA-Z]{2,3}$/i; break;
case "date": regExp = /^(19|20)\d{2}-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[0-1])$/; break;
case "phone": regExp = /^0(1[0-9]{8,9}|2[0-9]{7,8}|[3-6][0-9]{8}|70[0-9]{7,8}|50[0-9]{7,8}|80[0-9]{7,8})$/; break;
case "userid": regExp = /^[a-z][a-z0-9]{5,11}$/; break;
case "password": regExp = /^(?=.*[A-Za-z])(?=.*[0-9])[A-Za-z0-9!@#$%^&*()_\-+=\[{\]};:'",.<>\/?\\|`~]{8,20}$/; break;
case "db_table_name": regExp = /^[a-z](?:[a-z0-9]|_(?=[a-z0-9])){1,99}$/; break;
case "db_table_comment": regExp = /^[가-힣A-Za-z0-9\s()]{2,100}$/; break;
}
if (regExp.test(str)) {
return true;
} else {
return false;
}
}
휴대폰 번호 하이픈 포함
^\d{3}-\d{3,4}-\d{4}$
010-1234-5678→ 통과010-123-5678→ 통과01012345678→ 실패
하이픈이 포함된 휴대폰 번호만 허용할 때 적합합니다.
이메일
/^[0-9a-zA-Z]([-_\.]?[0-9a-zA-Z])*@[0-9a-zA-Z]([-_\.]?[0-9a-zA-Z])*\.[a-zA-Z]{2,3}$/i
기본적인 이메일 형식을 체크할 때 많이 씁니다.
다만 실무에서는 이메일 RFC 전체를 완벽하게 정규식으로 처리하기보다는,
1차는 정규식 검증, 2차는 실제 인증 메일 발송으로 가는 것이 더 안전합니다.
아이디
^[a-z][a-z0-9]{5,11}$
- 소문자로 시작
- 소문자 + 숫자 조합
- 6~12자
비밀번호
/^(?=.*[A-Za-z])(?=.*[0-9])[A-Za-z0-9!@#$%^&*()_\-+=\[{\]};:'",.<>\/?\\|~]{8,20}$/
(?=.*[A-Za-z])→ 영문 1개 이상 포함(?=.*[0-9])→ 숫자 1개 이상 포함- 특수문자 가능
- 8~20자
IPv4 주소
^(\d{1,3}\.){3}\d{1,3}$
192.168.0.1
127.0.0.1
URL 형식
^(https?:\/\/)?([a-z0-9\-]+\.)+[a-z]{2,6}$
http://test.co.kr
https://example.com
파일 확장자 검사 (이미지)
\.(jpg|jpeg|png|gif)$
photo.jpg
image.png
HTML 태그 제거
<[^>]*>
DB 테이블명
/^[a-z](?:[a-z0-9]|_(?=[a-z0-9])){1,99}$/
이 패턴은 꽤 실무적입니다.
- 첫 글자는 영문 소문자
- 이후는 소문자, 숫자, 언더스코어 허용
- 언더스코어 뒤에는 반드시 소문자/숫자가 와야 함
즉 이런 값은 가능하고: member, member_info, a1_table
이런 값은 막을 수 있습니다: _member, member_, member__info
정규표현식 사용할 때 실제로 느낀 주의점
정규표현식은 강력하지만, 모든 걸 정규식 하나로 끝내려고 하면 오히려 유지보수가 어려워집니다.
제가 실제로는 이렇게 나눠서 처리합니다.
1차: 정규식으로 형식 검사
- 입력 형식이 맞는가
- 허용하지 않는 문자가 들어왔는가
- 길이 조건을 만족하는가
2차: 서버에서 업무 규칙 검사
- 이미 존재하는 아이디인가
- 실제 가능한 날짜인가
- DB 예약어와 충돌하는가
- 금지어가 포함되어 있는가
이렇게 나누면 코드가 훨씬 읽기 쉬워집니다.
정규표현식만 믿으면 안 되는 이유
많은 초보 개발자가 실수하는 부분이 있습니다.
정규표현식이 통과했다고 해서 모든 데이터가 정상인 것은 아닙니다.
예를 들어
2026-02-31
은 날짜 정규표현식을 통과할 수 있습니다.
하지만 실제로 존재하지 않는 날짜입니다.
또한
999.999.999.999
도 단순한 IPv4 정규표현식을 통과할 수 있습니다.
따라서 정규표현식은 형식 검사만 담당하고, 실제 데이터 유효성 검사는 별도로 수행하는 것이 좋습니다.
JavaScript와 PHP를 함께 사용하는 방법
실무에서는 아래와 같은 구조를 추천합니다.
JavaScript
- 입력 즉시 검증
- 사용자 안내
- UX 향상
PHP
- 최종 저장 전 검증
- 보안 강화
- 데이터 무결성 유지
이렇게 이중 검증을 적용하면 대부분의 입력 오류를 예방할 수 있습니다.
마무리
정규표현식은 웹 개발에서 가장 자주 사용하는 도구 중 하나입니다.
회원가입, 게시판, 예약 시스템, 쇼핑몰, 관리자 페이지 등 거의 모든 입력 기능에서 활용할 수 있습니다.
제가 실제 프로젝트를 운영하면서 느낀 점은 정규표현식을 복잡하게 만드는 것보다 공통 함수로 관리하는 것이 훨씬 중요하다는 것입니다.
JavaScript와 PHP에 동일한 검증 규칙을 적용하고, 자주 사용하는 패턴을 함수로 정리해두면 유지보수 시간도 줄어들고 오류 발생률도 크게 감소합니다.
정규표현식을 처음 공부하는 분이라면 이 글에 있는 패턴부터 직접 적용해보는 것을 추천합니다.