38일차(1)/jsp(29) : 정규 표현식
** Regular Expression : 정규 표현식
- 프로그래밍 언어별로 따로 존재하는 것이 아니라 공통적으로 사용하는 표현식
- javascript 기준으로 // 안에 작성하는 문법
- 이 표현식을 배우면 어떤 문자열이 원하는 형식으로 만들어져 있는지 검증하거나,
특정 패턴으로 작성된 내용을 추출할 수 있다.
1. 정규표현식은 대소문자를 구분한다.
2. 눈에 보이지 않는 space, tab, new line(개행) 기호도 정확히 일치해야 한다.
- 공백이 여러개 있으면 다른 문자열로 인식한다.
3. 어떤 문자는 특별한 의미를 가지고 있다.
^ 는 매칭할 문자열의 시작을 의미한다.
$ 는 매칭할 문자열의 끝을 의미한다.
ex) 아래 문자열의 검증 결과는 다 다르다.
/who/ : who가 아무데나 있으면 된다.(있기만 하면 된다)
/^who/ : 반드시 who가 맨 앞에
/who$/ : 반드시 who가 맨 뒤에
/^who$/ : 앞에도 뒤에도 who만 있어야함 → who라는 문자만 있어야한다.
- /^who$/ 의 경우, who@who, who is who 이런것도 안된다.
-who@who의 경우, who가 아니라 who@who 로 시작하고 끝나는 문자열이다.
사이에 다른 것이 끼어있을 수 없다! 공백도 전부 인지된다고 생각하면 쉽다.
4.만일 특별한 의미를 가지고 있는 문자열의 literal 값이 필요하다면 역슬래시(\) 를 앞에 붙여주어야 한다.
- ^, $ 등이 검색하고 싶을 경우! 앞에 \ 를 붙이면 특별하게 해석을 하지않는다.
ex)
^$ : 아무것도 없어야 한다. 빈 문자열만 매칭된다.
\$ : $를 찾는다.
^\$ : $로 시작되는 것을 찾는다.
\$$ : $로 끝나는 것을 찾는다.
\\ : \를 찾는다.
5. . 점은 모든 문자를 의미한다
ex)
/./ : 아무거나 한 글자를 찾는다.(공백도)
/....../ : 아무거나 여섯 글자를 찾는다.(공백도)
all matches 로 찾으면 모든 문자를 6개씩 끊어서 찾는다.
- 위의 경우, 전체를 6자리씩 끊어서 찾아서, 맨 끝의 글자수는 5개이기 때문에 선택되지 않는다.
6. . 점의 literal 값이 필요하다면 역시 역슬래시(\) 가 필요하다
\. 으로 . 검색가능
/../. : 앞에도 . , 뒤에도 . 인 아무 문자! ex) . A .
7. [ ] 대괄호 안에는 매칭될수 있는 문자의 목록을 넣는다. 목록의 순서는 중요하지 않다.
- [] 는 한 글자를 의미한다. 한 글자가 될수있는 후보군이 들어있다.
- .점은 아무거나 한글자지만, [] 를 한 글자로 인정해주는 후보군이 괄호 안에 들어있다
ex) [oyu] : o또는 y 또는 u 를 찾아준다.
[owy][yow] : o w y 중 하나, y o w 중 하나! 총 2글자의 연속된 문자열을 찾는다.
ex) [dH]. : 앞에는 이 두 글자중 하나, . 위치에는 아무 글자나! 총 2개의 글자를 찾는 것
8. 문자의 범위는 [ - ] 문법으로 나타낼수 있다. 여러가지 범위도 하나의 표현식으로 쓸 수 있다.
- [A-Z] [가-나] [ㄱ-ㅎ] 한글도 가능하다.
ex) [ C-Ka-d2-6 ] : 한글자가 될 수 있는 후보군의 다양한 범위를 조합할 수 있다(하나의 표현식으로)
9. [ ] => 문자 클래스. 문자 클래스 안에 [^abc] 처럼 첫문자로 ^ 가 있다면 a,b,c 각각은 매칭하지 않을 문자 목록이 된다
- ^ 가 [ ]안에 있을 때는 not을 의미한다.
- 선택하지 않을 문자. 이 문자만 빼고!
10. 문자열을 교차 매칭 시키려면 소괄호 안에 | 로 구분해서 문자열을 나열하면된다. ( 문자열1 | 문자열2 | 문자열3 )
- or 개념. 1을 찾거나 2를 찾거나 3을 찾거나
ex) (Mon|Tues|Fri)day : 월, 화, 금요일을 추출
11. 수량자(Quantifiers) : * , + , ?
- 수량자는 문자가 몇번 올수 있는지 정의한다.
* : 0번이상 (없어도 되고 여러개가 있어도 된다)
+ : 1번이상 (반드시 있어야 하며 여러개가 있어도 된다)
? : 0 번 또는 1번 (없어도 되고 있다면 오직 한개만 허용
ex) aab, ab, b 가 있다면
/a*b/ : a가 0번 이상 반복된다(여러개 있어도 되고 없어도 됨) → aab, ab, b 추출
/a+b/ : a가 1번 이상 반복된다(반드시 있어야 된다) → aab, ab 추출
/a?b/ : a가 0번 또는 1번 이상 반복된다 → ab, ab, b 추출
-A*- : -A가 0번이상 반복된다.
[-@]* : - 또는 @ 가 0번 이상 반복된다.
12. 수량자 * 사용예 : 0 번 이상
ex).* : 모든 문자 0번 이상 (모든 문자 가능)
13. 수량자 + 의 사용예 : 1번 이상 (없으면 안됨)
ex)
\*+ : *을 1번 이상.
-@+- : - - 사이에 @가 1번이상 → -@@@- 추출
[^ ]+ : 공백이 아닌 한글자가 한번 이상 와야 한다. → 공백으로 구분된 단어들만 추출할 수 있다.(아래 예제의 my, name, is, banana)
14. 수량자 ? 사용예 : 0 번 또는 1번 (있어도 한번만 가능)
15. { } 는 정확한 문자의 반복횟수를 정의한다.
{ m } 는 m번 반복 (Case 1)
{ m,n } 는 최소 m 번 최대 n번 반복
{ m, } 는 최소 m번 반복
ex)
.{5} 아무거나 한글자를 다섯글자씩
[els]{1,3} 안의 문자(하나)가 {1,3} 최소 한번 최대 3번 반복
[a-z]{3,} 영문소문자 최소3회 반복( 3글자미만인 단어는 추출되지않는다)
16. 동일 표현
* 는 { 0, } 와 같다.
+ 는 { 1, } 와 같다.
? 는 { 0, 1 } 와 같다
ex) AA ABA ABBA ABBBA 가 있을 경우,
AB*A : A사이에 B가 0번이상 와야한다. → AA ABA ABBA ABBBA 추출
AB+A : 1번이상 → ABA ABBA ABBBA 추출
AB?A : 없거나 한번만 → AA ABA 추출
★자주 사용되는 정규 표현식★
(자주 쓰이기 때문에 줄임표현이 있다. 외워두기!)
[a-zA-Z0-9] → [\w]
- 영문 대소문자, 숫자 중에 1글자
[^a-zA-Z0-9] → [^\w] → [\W]
- 특수문자 1글자만 허용!
(소문자와 대문자는 반대 개념이라고 생각하면 편하다.)
[0-9] → [\d] (decimal의약자)
- 숫자 1글자만 허용
[^0-9] → [^\d] → [\D]
- 숫자가 아닌 문자 1글자
<Step08_regExp>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Step08_regExp.html</title>
</head>
<body>
<input type="text" id="inputMsg" placeholder="영문자 소문자만 입력..."/>
<p id="console"></p>
<script src="js/jquery-3.4.1.js"></script>
<script>
//영문자 소문자로만 이루어져 있는지를 검증할 정규 표현식 객체
var reg=/^[a-z]+$/;
// input 요소에 무언가 입력했을때 실행할 함수 등록
$("#inputMsg").on("input", function(){
//입력한 문자열을 읽어와서
var msg=$(this).val();
//영문자 소문자로만 이루어져 있는지 여부 알아내기
var isLowerCase=reg.test(msg);
//p 요소에 출력하기
$("#console").text(isLowerCase);
if(isLowerCase){
$(this).css("color","#00ff00");
}else{
$(this).css("color","#ff0000");
}
});
</script>
</body>
</html>
var reg=/^[a-z]+$/;
^$ : 시작과 끝
[a-z]+ : 영문자 소문자가 1번이상 반복. 영문자 소문자만 허용하겠다는 의미!
let str="abcd";
let str2="abcd1234";
let reg1=/^[a-z]+$/;
let reg1=/[a-z]/;
^ $ (시작과 끝)을 명시한 것과 하지 않은 것은 완전히 다르다!
- 명시하면: 하나라도 틀린게있으면 안된다.
- 명시하지 않으면: 만족시키는것이 어딘가 하나라도이쓰면 true이다.
- test() 함수에 통과하면(TRUE이면) 모두 표현식에 맞게 작성되었다는 의미이다.(검증과정)
- 정규표현식 객체는 / / 으로 감싸서 만든다.
- .test() 함수를 호출하면서 문자열을 집어넣으면
저 정규표현식을 만족하는지 여부를 리턴해준다.(boolean 타입)
- input 요소에 뭔가를 입력할 때마다 값을 받아와서 test()에 넣고 평가하여 정규 표현식에 만족하는지를 알아낸다.
var reg=/^[a-z]+$/;
- 영문자 소문자로만 이루어져 있는지를 검증할 정규 표현식 객체
- true-연두색 / false-빨간색으로 서식을 바꾼다.
- 콘솔창에서 test() 함수 테스트해보기
- reg 조건에 맞으면 true, 맞지 않으면 false를 반환!
<Step08_regExp2>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Step08_regExp2.html</title>
</head>
<body>
<button id="extractBtn">추출하기</button>
<ul>
</ul>
<script src="js/jquery-3.4.1.js"></script>
<script>
var str="My name is banana!";
//공백이 아닌 연속된 문자열을 찾아내는 정규표현식 객체
var reg=/[^ ]+/g;
$("#extractBtn").click(function(){
while(true){
//정규표현식에 매칭되는 문자열을 얻어낸다.
var result=reg.exec(str);
//매칭되는 문자열이 더이상 없으면 null 을 리턴한다.
if(result==null)break;
//li 요소를 동적으로 만들어서 text 출력하고 ul 에 추가
$("<li/>").text(result).appendTo("ul");
}
});
</script>
</body>
</html>
var reg=/[^ ]+/g;
- 공백이 아닌 연속된 문자열을 찾아내는 정규표현식 객체
- g는 global영역을 의미한다.
- 모든 영역에서 all matches를 찾아낼거라면 g를 써줘야 한다. 안그러면 하나밖에 찾지 못한다!
- 정규표현식 /[^ ]+/ 에 매칭되는 모든 문자열을 추출한다(반복문돌면서)
- exec() 함수 : 문자열을 받아 모두 다 추출한다.
<Step08_example>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Step08_example.html</title>
</head>
<body>
<form action="signup" method="post" id="signupForm">
<label for="id">아이디</label>
<input type="text" name="id" id="id"/><br/>
<label for="pwd">비밀번호</label>
<input type="text" name="pwd" id="pwd"/><br/>
<label for="phone">전화번호</label>
<input type="text" name="phone" id="phone" placeholder="010-1234-5678"><br/>
<button type="submit">가입</button>
</form>
<script src="js/jquery-3.4.1.js"></script>
<script>
/*
[ 검증조건 ]
아이디 : 영문자로 시작, 특수문자 허용하지 않음, 최소 5글자, 최대 10글자
비밀번호 : 특수문자 1개 , 대문자 1개 반드시 포함, 8글자 이상
[a-zA-Z0-9] => [/w]
[^a-zA-Z0-9] => [/W]
*/
var idReg=/^[a-zA-Z][a-zA-Z0-9]{4,9}$/;
var pwdReg1=/[\W]+/; //특수문자 포함 여부를 검증할 정규식
var pwdReg2=/[A-Z]+/; //영문자 대문자 포함여부를 검증할 정규식
var pwdReg3=/^.{8,}$/; //최소 8글자 이상인지 여부를 검증할 정규식
//핸드폰 번호를 검증할 정규표현식
var phoneReg=/^01[016789]-[0-9]{3,4}-[0-9]{4}$/;
/*
폼에 회원가입 정보를 입력하고 가입 버튼을 눌렀을때 위의 정규표현식
객체로 입력한 필드를 검사해서 매칭이 안된다면 매칭이 안되는 이유를
alert() 창으로 출력하고 폼 전송을 막아 보세요.
*/
$("#signupForm").on("submit", function(){
//입력한 아이디
var id=$("#id").val();
if(!idReg.test(id)){
alert("아이디를 영문자로 시작, \
특수문자 허용하지 않음, 최소 5글자, 최대 10글자, 입력하세요!");
return false; //폼 전송 막기
}
//입력한 비밀번호
var pwd=$("#pwd").val();
if(!pwdReg1.test(pwd)){
alert("비밀번호에 특수문자를 1개이상 포함 시키세요");
return false;
}
if(!pwdReg2.test(pwd)){
alert("비밀번호에 영문자 대문자를 1개이상 포함 시키세요.");
return false;
}
if(!pwdReg3.test(pwd)){
alert("비밀번호를 8글자 이상 입력하세요.");
return false;
}
//입력한 전화번호
var phone=$("#phone").val();
if(!phoneReg.test(phone)){
alert("전화번호를 형식에 맞게 입력하세요.");
return false;
}
});
</script>
</body>
</html>
var idReg=/^[a-zA-Z][a-zA-Z0-9]{4,9}$/; → 영문자로 시작, 최대 10글자
- 아이디 검증
- ^$ 시작과 끝 / [a-zA-Z] 맨앞 한글자는 영문자대소문자 / [a-zA-Z0-9]{4,9} 최소 4,최대 9(특수문자x)
var pwdReg1=/[\W]+/; → 특수문자 포함 여부
var pwdReg2=/[A-Z]+/; → 영문자 대문자 포함여부
var pwdReg3=/^.{8,}$/; → 최소 8글자 이상인지
- 비밀번호 검증
- 아무거나 한글자가 최소 8번이상 → 8글자 이상이어야 한다.
var phoneReg=/^01[016789]-[0-9]{3,4}-[0-9]{4}$/;
- 핸드폰 번호를 검증할 정규 표현식
- 이러한 검증 기능을 익히려는 것!
- 지금은 특정 패턴에 맞는 내용을 추출x 검증o
- 나중에는 특정문자열에서 원하는 패턴의 문자열을 추출해낼 수도 있다..
- 필요한 조건이 많을 경우: 정규표현식을 여러개 만들어서 여러번 검증한다.
- 조건에 맞지 않을경우 alert 창 나옴!
<signup_form.jsp> 수정 (정규표현식 추가)
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>/users/signup_form.jsp</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-Zenh87qX5JnK2Jl0vWa8Ck2rdkQ2Bzep5IDxbcnCeuOxjzrPF/et3URy9Bv1WTRi" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-OERcA2EqjJCMA+/3y+gxIOqMEjwtxJY7qPCqsdltbNJuaOe923+mo//f6V8Qbsw3" crossorigin="anonymous"></script>
<style>
h1{
margin: 20px 0px 20px;
border-bottom:3px solid #0d6efd;
padding:10px 0px 10px;
}
</style>
</head>
<body>
<jsp:include page="/include/navbar.jsp">
<jsp:param value="signupform" name="thisPage"/>
</jsp:include>
<div class="container">
<h1>회원 가입 폼입니다.</h1>
<form action="signup.jsp" method="post" id="signupForm">
<div>
<label for="id" class="control-label">아이디</label>
<input type="text" class="form-control" name="id" id="id" />
<small class="form-text text-muted">영문자 소문자로 시작하고 5글자~10글자 이내로 입력하세요.</small>
<div class="valid-feedback">사용할 수 있습니다.</div>
<div class="invalid-feedback">사용할 수 없는 아이디입니다.</div>
</div>
<div>
<label for="pwd" class="control-label">비밀번호</label>
<input type="password" class="form-control" name="pwd" id="pwd" />
<small class="form-text text-muted">특수 문자를 하나 이상 조합하세요.</small>
<div class="invalid-feedback">비밀번호를 확인하세요.</div>
</div>
<div>
<label for="pwd2" class="control-label">비밀번호 확인</label>
<input type="password" class="form-control" name="pwd2" id="pwd2" />
</div>
<div>
<label for="email" class="control-label">이메일</label>
<input type="text" class="form-control" name="email" id="email" />
<div class="invalid-feedback">이메일 형식에 맞게 입력하세요.</div>
</div>
<button class="btn btn-outline-primary" style="margin-top: 10px;" type="submit">회원가입</button>
</form>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.1/jquery.min.js"></script>
<script>
//유효성 여부를 저장할 변수를 만들고 초기값 대입
let isIdValid=false;
let isPwdValid=false;
let isEmailValid=false;
document.querySelector("#email").addEventListener("input", function(){
this.classList.remove("is-valid");
this.classList.remove("is-invalid");
//입력한 이메일
const inputEmail=this.value;
//이메일을 검증할 정규 표현식
const reg=/^[0-9a-zA-Z]([-_.]?[0-9a-zA-Z])*@[0-9a-zA-Z]([-_.]?[0-9a-zA-Z])*.[a-zA-Z]{2,3}$/i;
//만일 입력한 이메일이 정규표현식 검증을 통과하지 못했다면
if(!reg.test(inputEmail)){
this.classList.add("is-invalid");
isEmailVaild=false;
}else{//통과했다면
this.classList.add("is-valid");
isEmailVaild=true;
}
});
function checkPwd(){
//먼저 두개의 클래스를 제거하고
document.querySelector("#pwd").classList.remove("is-valid");
document.querySelector("#pwd").classList.remove("is-invalid");
//입력한 두개의 비밀번호를 읽어와서
const pwd=document.querySelector("#pwd").value;
const pwd2=document.querySelector("#pwd2").value;
//비교하기전에 정규표현식 검증
const reg=/[\W]/; // /[\W]/ 이어도 된다.
//만일 정규표현식 검증을 통과하지 못했다면
if(!reg.test(pwd)){
document.querySelector("#pwd").classList.add("is-invalid")
isPwdValid=false;
return;
}
//만일 비밀번호 입력란과 확인란이 다르다면
if(pwd != pwd2){
document.querySelector("#pwd").classList.add("is-invalid");
isPwdVaild=false;
}else{
document.querySelector("#pwd").classList.add("is-valid");
isPwdVaild=true;
}
}
document.querySelector("#pwd").addEventListener("input", function(){
checkPwd();
});
document.querySelector("#pwd2").addEventListener("input", function(){
checkPwd();
});
//id를 입력할때마다 호출되는 함수 등록
document.querySelector("#id").addEventListener("input", function(){
//input 요소의 참조값을 self에 미리 담아놓기
const self=this;
//일단 2개의 클래스를 모두 제거한 다음
self.classList.remove("is-valid");
self.classList.remove("is-invalid");
//1.입력한 아이디를 읽어와서
const inputId=self.value;
//아이디를 검즐할 정규표현식
const reg=/^[a-z].{4,9}$/; //처음은 영소문자, 다음은 아무글자나, 최대 4~9개까지, 끝을 명시
//입력한 아이디가 정규표현식과 매칭이 되는지(통과되는지)
const isMatch=reg.test(inputId)
//만일 매칭되지 않는다면
if(!isMatch){
self.classList.add("is-invalid")
isIdValid=false;
return; //함수를 여기서 끝내기
}
//2.서버에 페이지 전환 없이 전송을 하고 응답을 받는다.
fetch("checkid.jsp?inputId="+inputId)
.then(function(response){
return response.json();
})
.then(function(data){
//3. 사용가능한지 여부에 따라 id 입력란에 is-valid or is-invalid 클래스를 적절히 추가, 제거
console.log(data);
if(data.isExist){
self.classList.add("is-invalid")
isIdVaild=false;
}else{
self.classList.add("is-valid")
isIdVaild=true;
}
});
});
//폼에 submit이벤트가 일어났을 때 실행할 함수 등록
document.querySelector("#signupForm").addEventListener("submit", function(event){
//아래의 코드는 아이디, 비밀번호, 이메일 유효성 검증결과를 고려해서 조건부로 실행되도록 해야한다.
//폼 전체의 유효성 여부
const isFormValid= isIdValid && isPwdValid && isEmailValid;
//만일 폼이 유효하지 않으면
if(!isFormValid){
event.preventDefault(); //폼 전송 막기
}
});
</script>
<jsp:include page="/include/footer.jsp"></jsp:include>
</body>
</html>
<small class="form-text text-muted">영문자 소문자로 시작하고 5글자~10글자 이내로 입력하세요.</small>
<small class="form-text text-muted">특수 문자를 하나 이상 조합하세요.</small>
- input 아래에 넣어줄 안내문을 추가로 작성!
- 어떤 입력값의 유효성 조건: 정규표현식 통과 && 서버 필요조건 통과
* 서버에 전송하기 전에 정규표현식을 만족시키는지 확인한다.
const reg=/^[a-z].{4,9}$/;
const isMatch=reg.test(inputId)
if(!isMatch){
self.classList.add("is-invalid")
isIdValid=false;
return;
}
- 처음은 영소문자, 다음은 아무글자나, 최대 4~9개까지, 끝을 명시!
- isMatch가 false이면 해당 객체에 is-invalid 클래스를 추가한다.
- 정규표현식 if에서 통과(true)하면 fetch문으로 보내고
통과하지 못하면 return; 으로 함수를 끝내버린다!
const reg=/[\W]/; // /[\W]/ 이어도 된다.
if(!reg.test(pwd)){
document.querySelector("#pwd").classList.add("is-invalid")
isPwdValid=false;
return;
}
- reg.test(pwd)의 결과가 false이면 해당 객체에 is-invalid 클래스를 추가한다.
- 정규표현식을 통과하지 못하면 비밀번호 input 2개의 값이 같은지 비교할 필요가 없다.
- return으로 함수 끝내버리기!
- 이메일의 경우
const reg=/^[0-9a-zA-Z]([-_.]?[0-9a-zA-Z])*@[0-9a-zA-Z]([-_.]?[0-9a-zA-Z])*.[a-zA-Z]{2,3}$/i;
- @, . 등의 조건을 넣어 정규표현식 만들기
참고) 문자열 안에서 \ (역슬래시) 를 사용시 주의해서 사용하기
- \ 는 특별한 의미를 갖고 있으므로, 문자열 안의 \는 조심해서 사용해야 한다.
- \ 는 보통 뒤에 따라오는 특수한 의미의 문자를 그냥 문자로 인식시키고 싶을 때 사용한다.
- \ 를 출력하고 싶은 경우
new RegExp(" \* ") → 이렇게 출력하고 싶은 경우,
new RegExp(" \\* ") → 이렇게 역슬래시 두개를 작성해야 출력된다.
- 문자로서의 \를 인지시키려면 \\로 작성해야 한다.
'국비교육(22-23)' 카테고리의 다른 글
38일차(3) : Vue.js 예제(2) (0) | 2022.12.01 |
---|---|
38일차(2) : Vue.js 예제(1) (1) | 2022.12.01 |
37일차(4)/jsp(28) : jQuery 예제 (1) | 2022.11.30 |
37일차(3)/jsp(27) : jQuery 기초 (0) | 2022.11.29 |
37일차(2)/jsp(26) : cookie 예제 (0) | 2022.11.29 |