Day 42. 웹 프론트 9 ( 정규표현식 )

ho_c·2022년 4월 16일
0

국비교육

목록 보기
42/71
post-thumbnail
post-custom-banner

이번 시간에는 정규 표현식을 배웠다. ‘아니 어제까지만 해도 API 다루다가 갑자기 정규표현식이요?’라는 생각이 들었지만, 우리의 목적은 원하는 대상을 찾는 것이다.

그럼 찾기만 해요?

사실 중요한 것은 찾는 것이다. 하지만 찾은 다음에 그 결과를 가지고 할 수 있는 것은 매우 많다. 예를 들어 어떤 웹사이트의 패턴을 분석하고, 거기서 원하는 정보들만 출력해서 내 사이트에서 또 다른 디자인으로 끌어다 쓸 수도 있다. (물론 저작권은 필수!)

또는 특정 태그만 추출하는 기능을 구현할 수도 있고, 복잡하거나 애매한 문자열들을 조건문을 쓰지 않고 분석해낼 수 있다. 이처럼 정규식의 사용은 프로그래밍언어에 국한되지 않기 때문에 다양한 응용이 가능하다.

📝목차

  1. 정규표현식
  2. 자바스크립트에서 사용

1. 정규 표현식(Regular expression)이란?

정규 표현식은 자바스크립트 전용이 아닌, 모든 언어에서 범용적으로 사용되는 문법이다.
이는 어떤 언어에 종속되지 않고 고유의 문법으로 일종의 검색 기법이라 할 수 있다.

그 특징은 다음과 같다.

  • 특정 문자열 내에서 특정 패턴을 이용하여 대상을 검색하는 문법
  • 일종의 검색 기법, 이로부터 응용되고 확장된 솔루션들이 많다.
  • 패턴을 이용해서 검색하기에 정밀한 검색이 가능하다.
  • 위와 함께 추상적인 검색도 가능하다.
  • 텍스트를 분석할 수 있는 모든 곳에서 최고의 효율을 가진다.

[ 기본 구조 ]

/ 정규표현식 /flags

1. flags : 정규 표현식이 적용될 때 활용할 설정

  • g: 하나의 검색이 성공해도 중단하지 않고 모든 텍스트에서 전부 검색하는 옵션(전체 검색 옵션)
    일반적인 검색은 좌측에서 우측으로 가고, 대상을 찾으면 검색을 끝낸다

  • i : 대소문자를 가리지 않고 검색하는 옵션

  • s : .기호가 개행문자 등의 특수 문자까지 모두 매칭시키게 변경하는 옵션
    . 기호는 기본으로 \n, \t와 같은 특수 문자와 매칭되지 않음.

  • m : \n을 기준으로 모든 문단을 독립적으로 분석하기 위한 옵션


2. 주요 문법

(1) . : 개행문자와 특수문자를 제외한 모든 단일 문자를 가리킨다.

예시

t.e : t로 시작해서 아무거나 한 글자가 오고 e로 끝나는 패턴
t..e : t로 시작해서 아무거나 두 글자가 오고 e로 끝나는 패턴

이때, “.”을 검색하고 싶으면 .을 해줘야 한다.


(2) ^ $

^... : 문단의 맨 처음에서 검색
→ 해당 기호를 사용하면 문장의 시작점에 있는 것만 검색한다.

...$ : 문단의 맨 마지막에서 검색
→ 해당 기호를 사용하면 문장의 끝에 있는 것만 검색한다.

^...$ : 문자 그 자체를 의미한다. 곧, 문장의 맨 앞이자, 맨 뒤어야 한다.


(3) []

  • 괄호 내에 있는 문자 중에 한 글자와 매칭을 시켜 검색한다.
  • 이때, 내부에 들어가는 것은 한 글자씩 봐야 한다.
  • 내부에 [^]가 들어가면 not이 된다.

예시

Gr[abcde∙]y = Gray, Grby, Grcy, Grdy, Grey, Gr∙y
[^abcd] : a, b, c ,d 가 안들어가는 것 

응용

[a-z] : a~z까지
[a-zA-Z0-9] : 모든 글자
숫자 : \d == 0~9

(4) ?

  • 기호의 바로 앞 단일 문자가 있어도 되고, 없어도 되는 상태를 검색.
    예시) th?e : the or te

  • 수량자( +, *, {} ) 뒤에서 사용하면 최단 매치(Lazy Match)를 하게한다.


[ 수량자 ]

  • 수량자는 대상 문자, 단어의 수를 기준으로 검색한다.
  • 기본값은 Greedy로 최대한의 범위에서 일치하는 경우를 검색하려 한다.
  • 위 경우, 패턴에 따라 검색하기 어렵기에 ?을 사용해 최단 매치를 실행하게 한다.

(5) + : 기호 바로 앞에 한 문자에 대해 1개 이상일 때를 검색

  • .+을 하게 되면 모든 문자가 1개 이상일 때를 탐색하므로 문장 전체를 찾는다. (/./과 다름)
  • 위 경우 greedy이면 최장값을 반환하기 때문에 .+?을 사용한다.

예시

/gskin+er/
gskinner, gskinnner, gskinnnner 

(6) * : 기호 바로 앞에 한 문자에 대해 0개 이상일 때를 검색

예시

/go*gle/
ggle, google, gogle

(7) {} : 바로 앞 한 문자에 대해서 지정한 개수 일 때를 검색

예시

{2} : 2개
{2,} : 2개 이상
{2, 4} : 2개 이상 4개 이하

전화번호 : ^01[\d]-*[\d]{4}-*[\d]{4}$
ID : ^[a-z_][a-z0-9_]{5,9}$

(8) ()

  • 정규표현식의 적용 대상을 그룹화하는 문법
  • 제일 중요한 기능으로 그룹화된 대상들을 따로 뽑아낼 수 있다.

예시

  • or 연산이 가능하다.

    	/Gr(a | e)y/
    	( a | e ) : ae 이거나 ed 이거나.
    	Gray, Grey
  • 그룹화하여 한 단어로 만들어 줄 수 있다.

    	/go(og)+le/
    	googogle
    	googogogle

여기서부터는 실제 프로그래밍 상에서 사용법이랑 다르다. 자바스크립트에서 정규표현식은 하나의 객체로 검색을 하면, 그 결과를 주로 배열의 형태로 다루게 된다. 따라서 해당 결과들이 배열에 저장되는데, 그때 regex의 멤버필드로 저장된다.

(8-1) 캡쳐변수 $& (멤버 필드)

변수명이 $&으로 여기에는 검색에 성공한 모든 데이터를 저장하며 배열에선 index[0]이다.
이때 변수는 통제할 수 없는 only-read만 가능한 변수이다.

(8-2) 그룹화 캡쳐 변수 $n

검색에 성공하면 캡쳐 변수에 묶이는 것처럼 그룹화된 데이터는 따로 뽑혀 변수에 묶이며, 배열에선 index[1]부터 시작된다.

이런 정규표현식을 응용하는 법은 대상 HTML의 패턴을 분석하고, 그 패턴에 맞게 정규표현식을 작성하는 것이다. 이때, 요소의 id값이 어떻게 구성되었는지를 먼저 확인하는 것이 좋다.


그럼 실제 자바스크립트에선 어떻게 사용되는지 알아보자.

2. 자바스크립트에서 사용

JS, JAVA 모두 정규표현식은 하나의 객체로서 존재하며, 그 안에 여러 메서드와 변수들이 존재한다. 또한 정적이라서 언제든지 사용할 수 있다.

[ 기본 사용법 ]

자바스크립트에서 사용법은 두 가지이다.

1) 객체를 생성하여 사용하기

  • 별로 어렵지 않으며, 그렇게 많이 사용하진 않는다.
let regex = new RegeExp();

2) 쿼리문으로 사용하기

  • //으로 쿼리문을 작성하면 자동으로 객체가 생성된다.
// 검색 대상
let str = "안녕하세요. 저는 Jack 입니다. 010-1116-2131 또는 010-1234-1234 로 연락주세요.";

// 쿼리문
let regex = /(01[\d]-?[\d]{3,4}-?[\d]{4}) 또는 (01[\d]-?[\d]{3,4}-?[\d]{4})/g;

[ 정규식 적용 함수 ]

정규식에서 사용하는 함수는 대표적으로 두 가지가 있다.

1) .test

  • 정규식에 매치되는 데이터가 존재한다면 true 반환, 반대는 false 반환
let = result = regex.test(str);
console.log(result); // 데이터가 존재함으로 true를 반환.

2) .exec

  • 정규식에 매치되는 데이터를 발견한다면 자세한 정보를 포함하여 배열 형태로 반환.
  • 실제 응용되는 메서드로 위의 캡처변수가 반환 배열에 담긴다. (인덱스로 호출)
  • 물론 배열 안의 멤버필드로도 가져올 수 있다. (.n,.n, .)
regex.exec(str);
console.log(RegExp.$); // 전체 캡처변수 
console.log(RegExp.$1 + " : " + RegExp.$2); // 첫 번째, 두 번째 그룹 캡처 변수

[ g flags ]

실사용에서 g 플래그가 전체 탐색을 가능하게 하는 원리는 g가 검색 과정에서 세이브 포인트로 동작하기 때문이다. 실제 우리가 .exec로 검색할 때는 무한 반복문을 통해서 다음과 같이 실행한다.

let regex = /alt="(.+?)".+?(\d.\d\d)</gs;

while (true) {
	let result = regex.exec(str); 
	if (result == null) {
		break;
	} 
	console.log(result[1]);
	console.log(result[2]);
}

위 상황에서 정규식은 하나의 패턴 안에서 2개의 그룹을 뽑아내고자 한다. 그러나 전체에서 해당 패턴은 열 번이 존재한다고 가정할 때, 출력값은 총 20개가 나와야 한다.

즉, 반복문에서 .exec 는 한 패턴씩 분석한다. 이때 g 플래그를 붙이지 않는다면 무한 반복에 빠지게 된다. 이는 검색 방식과 관련이 있는데 정규식은 검색이 완료되면 다시 처음으로 검색을 시작한 위치로 돌아가게 된다.

그렇게 된다면, 정규식은 계속 똑같은 대상을 검색하고 이를 배열로 반환할 것이기에 if문 안의 break가 동작하지 않는다. 따라서 g 플래그를 붙여주게 된다면 검색 완료 후, 그 위치에 세이브를 하게 된다.

그래서 검색 결과 이후로 또 새로운 검색을 해나가게 되며, 결과적으로 대상 문장의 끝까지 탐색하고 더 이상 결과가 없으면 null을 반환한다. 실제로 위의 반복문을 없앨지라도 정규식은 한 패턴의 그룹들만 반환한다.

profile
기록을 쌓아갑니다.
post-custom-banner

0개의 댓글