정규표현식

lim1313·2021년 8월 6일
0

TILPLUS

목록 보기
3/40

정규표현식 사용하기

정규표현식을 컴파일해서 객체 만들기

리터럴 패턴

let pattern = /a/;

생성자 함수 호출

let pattern = new RegExp('c');
// new 를 이용해서 정규 표현식 객체를 생성

정규표현식 내장 메소드

🍀 RegExp 객체의 메소드

RegExp.exec()

문자열에서 원하는 문자 찾아내기
배열 || null 리턴

let pattern = /a/;
pattern.exec('abcedf') // ["a"]
pattern.exec('ghijk') // null
let pattern = /a./;
pattern.exec('abcedf') // ["ab"]
pattern.exec('ghijk') // null

RegExp.test()

인자 안에 패턴에 해당하는 문자열이 있으면 true, 없으면 false
존재 유무 판단
boolean 리턴

pattern.test('abcdef') // true
pattern.test('defghi') // false

🍀 String 객체의 메소드

String.match()

문자열에서 정규표현식 활용
배열 || null 리턴

let pattern = /a/
let str = "abcde"
str.match(pattern) // ["a"]

let str = "defgh"
str.match(pattern) // null

String.replace()

첫 번째 인자로는 정규표현식을 받고, 두 번째 인자로는 치환하려는 문자열을 받는다.
치환하려는 문자열로 변경 후 변경된 값을 리턴

let pattern = /a/
let str = "abcde"
str.replace(pattern,"A") // "Abcde"
let pattern = /(\w+)\s(\w+)/
let str = "coding everybody"
let result = str.replace(pattern, "$2, $1")
console.log(result)
// everybody, coding
// $1 , $2는 첫번째 그룹, 두번째 그룹을 의미 

String.search()

정규표현식을 인자로 받아 가장 처음 매칭되는 부분 문자열의 위치를 반환
매칭되는 문자열이 없으면 -1을 반환

"JavaScript".search(/script/); // -1 대소문자를 구분
"JavaScript".search(/Script/); // 4
"codestates".search(/ode/); // 1

플래그 flag

정규표현식은 플래그를 설정해 줄 수 있으며, 플래그는 추가적인 검색 옵션의 역할을 해 준다.
이 플래그들은 각자 혹은 함께 사용하는 것이 모두 가능하며, 순서에 구분이 없다.

구분특징예시
i대소문자 구분하지 않음/a/i
g검색된 모든 결과를 리턴 / g 가 없으면 첫 번째 검색 결과만 반환/a/g
ig대소문자 구분없이 패턴에 해당하는 모든 문자/a/ig/
m다중행을 검색/c/gm
let withi = /c/i;
let withouti = /c/;
"CodeGood".match(withi); // ['C']
"CodeGood".match(withouti); // null
let withg = /c/g;
let withoutg = /c/;
"coolcode".match(withg); // ['c', 'c']
"coolcode".match(withoutg); // ['c'] g 가 없으면 첫 번째 검색 결과만 반환합니다
let str = `1st : cool
2nd : code
3rd : states`;
str.match(/c/gm)
// 3개의 행을 검색하여 모든 c 를 반환합니다.
// ['c', 'c']
str.match(/c/m)
// m은 다중행을 검색하게 해 주지만, g 를 빼고 검색하면 검색 대상을 찾는 순간 검색을 멈추기 때문에
// 첫 행의 ['c'] 만 리턴합니다.

Quantifiers

구분특징
?0번 혹은 1번 나타나는 경우
*없거나 하나 이상
+하나이상
{n}n번 반복
{min,}최소
{min,max}최소, 최대
/gra?y/gm  --> a가 있거나 없거나
/gra{2,4}y/gm --> a가 최소2개 최대 4개

"codee coding codeeeeee codingding".match(/ode*/g);
// ["odee", "od", "odeeeeee", "od"]

"code codee coding codeeeeee codingding".match(/ode+/g);
// ["ode", "odee", "odeeeeee"]
"co cod code codee coding codeeeeee codingding".match(/ode?/g);
// ["od", "ode", "ode", "od", "ode", "od"]
"co cod code codee coding codeeeeee codingding".match(/ode*?/g);
// ["od", "od", "od", "od", "od", "od"]
"co cod code codee coding codeeeeee codingding".match(/ode+?/g);
// ["ode", "ode", "ode"]

"co cod code codee coding codeeeeee codingding".match(/ode{2}/g);
// 2개의 "e"를 포함한 문자열을 검색합니다.
// ["odee", "odee"]

"co cod code codee coding codeeeeee codingding".match(/ode{2,}/g);
// 2개 이상의 "e"를 포함한 문자열을 검색합니다.
// ["odee", "odeeeeee"]

"co cod code codee coding codeeeeee codingding".match(/ode{2,5}/g);
// 2개 이상 5개 이하의 "e"를 포함한 문자열을 검색합니다.
// ["odee", "odeeeee"]

Groups and ranges

구분특징
|또는
( )그룹
[ ]문자셋, 괄호안의 어떤 문자든
[^] 부정 문자셋 괄호 안의 어떤 문자가 아닐때
(?:)찾지만 기억하지는 않음

[abc] // a or b or c 를 검색. or(|) Operator 로 작성한 a|b|c 와 동일하게 작동.

[a-c] // [abc] 와 동일. - 로 검색 구간을 설정할 수 있다.

"AA 12 ZZ Ad %% Az !# dd 54 zz".match(/[A-Z]+/gi);
// flag i 는 대소문자를 구분하지 않기 때문에 위와 동일한 결과를 반환합니다.
// ["AA", "ZZ", "Ad", "Az", "dd", "zz"]

"AA 12 ZZ Ad %% Az !# dd 54 zz".match(/[0-9]+/g);
// 숫자도 검색 가능합니다.
// ["12", "54"]

"aAbB$#67Xz@9".match(/[^a-zA-Z]+/g);
// [] 안에 ^ 를 사용하면 anchor 로서의 문자열의 처음을 찾는것이 아닌 
// 부정을 나타내기 때문에 [] 안에 없는 값을 검색합니다.
// ["$#67", "@9"]

Boundary-type

구분특징
\b단어 경계
\B단어 경계가 아님
^문장의 시작
$문장의 끝
/\bYa/gm 단어 앞에서 쓰이는 Ya만 선택 
/Ya\b/gm 단어 뒤에서 쓰이는 Ya
/Ya\B/gm 단어 뒤에서 쓰이지 않는 Ya
/\BYa/gm 단어 앞에서 쓰이지 않는 Ya

/^Ya/gm 문장의 시작에서 쓰이는 Ya
/Ya$/gm 문장의 끝에서 쓰이는 Ya

Character classes

구분특징
\ 특수 문자가 아닌 문자
.어떤 하나의 글자 (줄바꿈 문자 제외)
\ddigit 숫자 / [0-9]
\Ddigit 숫자가 아님 / [^0-9]
\w알파벳 대소문자, 숫자, _(underbar) / [a-zA-Z0-9_]
\W대소문자, 숫자, _ (underbar)가 아닌 문자 / [^a-zA-Z0-9_]
\sspace 공백
\S띄어쓰기를 제외한 모든 문자
let pattern = /a./;
pattern.exec('abcedf') // ["ab"]
console.log('abc34'.match(/\d/)); // ["3"]
console.log('abc34'.match(/[0-9]+/)); // ["34"]
console.log('abc34'.match(/\d/g)); // ["3", "4"]
console.log('abc34'.match(/[0-9]+/g)); // ["34"]
"ab3_@A.Kr".match(/[a-zA-Z0-9_]/) // ["a"]
"ab3_@A.Kr".match(/\w/g); //["a", "b", "3", "_", "A", "K", "r"]

"ab3_@A.Kr".match(/\W/); // ["@"]
"ab3_@A.Kr".match(/\W/g); // ["@", "."]

Grouping and capturing

그룹화

표현식의 일부를 ()로 묶어주면 그 안의 내용을 하나로 그룹화할 수 있다.

let co = 'cococo';
let cooo = 'cooocooo';

co.match(/co+/); // ["co", index: 0, input: "coco", groups: undefined]
cooo.match(/co+/); // ["cooo", index: 0, input: "cooocooo", groups: undefined]

co.match(/(co)+/); // ['cococo', 'co', index: 0, input: 'cococo', groups: undefined]
cooo.match(/(co)+/); // ["co", "co", index: 0, input: "cooocooo", groups: undefined]

co.match(/(co)+/g); // ['co', 'co']
cooo.match(/(co)+/g); // ['cococo']

캡쳐

() 로 그룹화한다고 하였고, 이를 캡처한다

예시 1

co.match(/(co)+/); // ["coco", "co", index: 0, input: "coco", groups: undefined]
  1. ( ) 로 "co"를 캡처
  2. 캡처한 "co" 는 일단 당장 사용하지 않고, + 가 "co"의 1회 이상 연속 반복을 검색
  3. 이렇게 캡처 이외 표현식이 모두 작동하고 나면, 캡처해 두었던 "co"를 검색
    따라서 2번 과정에 의해 "coco" 가 반환되고, 3번에 의해 "co"가 반환되는 것

예시2

"2021code".match(/(\d+)(\w)/);
// ["2021c", "2021", "c", index: 0, input: "2021code", groups: undefined]
  1. () 안의 표현식을 순서대로 캡처 ⇒ \d+ 와 \w
  2. 캡처 후 남은 표현식으로 검색 ⇒ 이번 예시에는 남은 표현식은 없음.
  3. \d 로 숫자를 검색하되 + 로 1개 이상 연속되는 숫자를 검색 ⇒ 2021
  4. \w 로 문자를 검색 ⇒ c
  5. 3번과 4번이 조합되어 "2020c" 가 반환
  6. 첫 번째 캡처한 (\d+) 로 인해 2021 이 반환
  7. 두 번째 캡처한 (\w) 로 인해 "c" 가 반환
'2021code'.match(/(\d+)(\w)+/)
// ['2021code', '2021', 'e', index: 0, input: '2021code', groups: undefined]

문자열 대체 시 캡처된 값 참조

캡처된 값은 replace() 메소드를 사용하여 문자 치환 시 참조 패턴으로 사용될 수 있다.

"code.states".replace(/(\w+)\.(\w+)/, "$2.$1"); //states.code

non-capturing

(?:)로 사용하면 그룹은 만들지만 캡처는 하지 않는다.

let co = 'coco';

co.match(/(co)+/); // ["coco", "co", index: 0, input: "coco", groups: undefined]

co.match(/(?:co)+/); 
// ["coco", index: 0, input: "coco", groups: undefined]

lookahead

(?=) 는 검색하려는 문자열에 (?=여기) 에 일치하는 문자가 있어야 (?=여기) 앞의 문자열을 반환.

"abcde".match(/ab(?=c)/);
// ab 가 c 앞에 있기 때문에 ["ab"] 를 반환
"abcde".match(/ab(?=d)/);
// d 의 앞은 "abc" 이기 때문에 null 을 반환

negated lookahead

(?!) 는 (?=) 의 부정

"abcde".match(/ab(?!c)/); // null
"abcde".match(/ab(?!d)/); // ["ab"]

전방탐색

let price = "2820원입니다."

let pattern = /(?=0원).*/g
str.match(pattern) //-> 0원입니다.

let pattern = /[0-9]*(?=0원)/g
str.match(pattern) //-> 282

let pattern = /[0-9]*(?=0원).*/g
str.match(pattern) //-> 2820원입니다.
let pattern =  /(?=:).*/g
let str = "http://www.naver.com"
console.log(str.match(pattern));
//["://www.naver.com"]

let pattern2 =  /(?=.*:).*/g
console.log(str.match(pattern2));
//["http://www.naver.com"]

활용 예시

비밀번호

최소 8자 이상하면서, 알파벳과 숫자 및 특수문자(@$!%*#?&) 는 하나 이상 포함

 let pattern = /^(?=.*[A-Za-z])(?=.*\d)(?=.*[@$!%*#?&])[A-Za-z\d@$!%*#?&]{8,}$/

 let str = "aaa@aaa1"
 console.log(str.match(pattern));
 console.log(pattern.test(str));

전화번호

01033333333
010-1110-1111
010 0000 0000
010.2222.2222
02-3333-3333

let num = '010 5555 4444';
let re = /\d{2,3}[- .]?\d{4}[- .]?\d{4}/gm;
let found = re.test(num);
let regExp = /^01([0|1|6|7|8|9]?)-?([0-9]{3,4})-?([0-9]{4})$/;

이메일

hello.bye@nevar.com
hello@nevaer.com
hello_good+bye@goood.net

let regExp = /^[0-9a-zA-Z]([-_.]?[0-9a-zA-Z])*@[0-9a-zA-Z]([-_.]?[0-9a-zA-Z])*.[a-zA-Z]{2,3}$/i;

http://youtube.be/-AioebdoDem
주소에서 비디오 번호 추출하기(-AioebdoDem)

let pattern = /^(?:https?:\/\/)?(?:www\.)?[\w]+\.[\w]+\/([\w-]+)$/
// ?:  -> 그룹은 지정하지만 사용하지 않을 그룹이기 때문에 ?:을 해준다.

let result = pattern.exec("youtube.be/-ZclicWozm")

let str = "http://youtube.be/-AioebdoDem"
let result2 = str.match(pattern)

console.log(result);
console.log(result2[1]); //->"-AioebdoDem"

정규표현식 빌더)
https://regexr.com/

profile
start coding

0개의 댓글