Thanks to visit codestin.com
Credit goes to ko.javascript.info

2022년 8월 1일

패턴과 플래그

정규 표현식(regular expression)은 문자 검색과 교체에 사용되는 패턴으로 강력한 기능을 제공합니다.

자바스크립트에선 RegExp 객체와 문자열 메서드를 조합해 정규표현식을 사용할 수 있습니다.

정규 표현식

정규 표현식(‘regexp’ 또는 'reg’라고 줄여서 사용)은 패턴(pattern) 과 선택적으로 사용할 수 있는 플래그(flag) 로 구성됩니다.

정규식 객체를 만들 땐 두 가지 문법이 사용됩니다.

‘긴’ 문법은 다음과 같습니다.

regexp = new RegExp("pattern", "flags");

‘짧은’ 문법은 슬래시(빗금) "/"를 사용합니다.

regexp = /pattern/; // 플래그가 없음
regexp = /pattern/gmi; // 플래그 g, m, i가 있음(각 플래그에 대해선 곧 다룰 예정)

슬래시 "/"는 자바스크립트에게 정규 표현식을 생성하고 있다는 것을 알려줍니다. 문자열에 따옴표를 쓰는 것과 동일한 역할을 하죠.

짧은 문법을 사용하든 긴 문법을 사용하든 상관 없이 위 예시에서의 regexp는 내장 클래스 RegExp의 인스턴스가 됩니다.

두 문법의 중요한 차이점은 /.../를 사용하면 문자열 템플릿 리터럴에서 ${...}를 사용했던 것처럼 중간에 표현식을 넣을 수 없다는 점입니다. 슬래시를 사용한 방법은 완전히 정적입니다.

슬래시를 사용한 짧은 문법은 코드를 작성하는 시점에 패턴을 알고 있을 때 사용합니다. 아마 대다수가 이런 경우에 속할 겁니다. 반면 new RegExp를 사용한 긴 문법은 ‘상황에 따라’ 동적으로 생성된 문자열을 가지고 정규 표현식을 만들어야 할 때 주로 사용합니다. 관련 예시를 살펴봅시다.

let tag = prompt("어떤 태그를 찾고 싶나요?", "h2");

let regexp = new RegExp(`<${tag}>`); // 프롬프트에서 "h2"라고 대답한 경우, /<h2>/와 동일한 역할을 합니다.

플래그

정규 표현식엔 검색에 영향을 주는 플래그를 선택적으로 붙일 수 있습니다.

자바스크립트는 6개의 플래그를 지원합니다.

i
i 플래그가 붙으면 대·소문자 구분 없이 검색합니다. 따라서 Aa에 차이가 없습니다(아래 예시 참조).
g
g 플래그가 붙으면 패턴과 일치하는 모든 것들을 찾습니다. g 플래그가 없으면 패턴과 일치하는 첫 번째 결과만 반환됩니다.
m
다중 행 모드(multiline mode)를 활성화합니다. 자세한 내용은 앵커 ^와 $의 여러 행 모드, 'm' 플래그에서 다룰 예정입니다.
s
.이 개행 문자 \n도 포함하도록 ‘dotall’ 모드를 활성화합니다. 자세한 내용은 문자 클래스에서 다룰 예정입니다.
u
유니코드 전체를 지원합니다. 이 플래그를 사용하면 서로게이트 쌍(surrogate pair)을 올바르게 처리할 수 있습니다. 자세한 내용은 유니코드: 'u' 플래그와 \p{...} 클래스에서 다룰 예정입니다.
y
문자 내 특정 위치에서 검색을 진행하는 ‘sticky’ 모드를 활성화 시킵니다. 자세한 내용은 Sticky flag "y", searching at position에서 다룰 예정입니다.
색상

정규 표현식을 설명할 때 사용되는 밑줄의 색상은 각각 다음과 같은 상징이 있습니다.

  • 정규표현식 – 빨강
  • 검색할 문자열 – 파랑
  • 검색 결과 – 초록

str.match로 검색하기

앞서 언급한 바와 같이 정규 표현식은 문자열 메서드와 조합하여 사용합니다.

str.match(regexp)를 호출하면 문자열 str에서 regexp와 일치하는 것들을 찾아내는 식으로 말이죠.

str.match엔 세 가지 모드가 있습니다.

  1. 정규 표현식에 플래그 g가 붙으면 패턴과 일치하는 모든 것을 담은 배열을 반환합니다.

    let str = "We will, we will rock you";
    
    alert( str.match(/we/gi) ); // We,we (패턴과 일치하는 부분 문자열 두 개를 담은 배열)

    대·소문자 구분 없이 검색을 할 수 있도록 하는 플래그 i를 사용했기 때문에 Wewe 모두가 반환되었습니다.

  2. 플래그 g가 붙지 않은 경우엔 패턴에 맞는 첫 번째 부분 문자열만 담은 배열을 반환합니다. 해당 문자열은 배열 인덱스 0에 저장되는데 이 문자열의 프로퍼티엔 상세한 추가 정보가 저장됩니다.

    let str = "We will, we will rock you";
    
    let result = str.match(/we/i); // 플래그 g 없음
    
    alert( result[0] );     // We (패턴에 일치하는 첫 번째 부분 문자열)
    alert( result.length ); // 1
    
    // Details:
    alert( result.index );  // 0 (부분 문자열의 위치)
    alert( result.input );  // We will, we will rock you (원본 문자열)

    그런데 정규 표현식을 괄호로 둘러싼 경우엔 메서드 호출 시 반환되는 배열에 0 이외에도 다른 인덱스가 있을 수 있습니다. 자세한 내용은 Capturing groups에서 다루겠습니다.

  3. 플래그 g의 유무와 상관없이 패턴과 일치하는 부분 문자열을 찾지 못한 경우엔 null이 반환됩니다.

    일치하는 부분 문자열이 없는 경우엔 빈 배열이 아닌 null을 반환한다는 점은 아주 중요한 차이점입니다. 이런 점을 잊고 코딩 하다 보면 다음과 같이 에러가 발생할 수 있습니다.

    let matches = "JavaScript".match(/HTML/); // matches엔 null이 저장됨
    
    if (!matches.length) { // TypeError: Cannot read property 'length' of null
      alert("바로 윗줄에서 에러가 발생합니다.");
    }

    str.match 호출 결과가 항상 배열이 되게 하려면 아래와 같은 방법을 사용하면 됩니다.

    let matches = "JavaScript".match(/HTML/) || [];
    
    if (!matches.length) {
      alert("정규 표현식과 일치하는 부분 문자열이 없습니다."); // 이제 에러없이 잘 동작하네요.
    }

str.replace로 치환하기

메서드 str.replace(regexp, replacement)를 사용하면 str 내 부분 문자열 중 regexp에 일치하는 부분 문자열을 replacement로 교체할 수 있습니다. 이때 플래그 g가 있으면 모든 부분 문자열이 교체되고, 그렇지 않으면 첫 번째 부분 문자열만 교체됩니다.

예시:

// 플래그 g 없음
alert( "We will, we will".replace(/we/i, "I") ); // I will, we will

// 플래그 g 있음
alert( "We will, we will".replace(/we/ig, "I") ); // I will, I will

여기서 두 번째 인수 replacement는 문자열인데, 문자열 안에 다음과 같은 특수 문자를 넣어주면 독특한 방식으로 문자열을 교체할 수 있습니다.

특수 문자 교체 방식
$& 패턴과 일치하는 부분 문자열
$` inserts a part of the string before the match
$' inserts a part of the string after the match
$n if n is a 1-2 digit number, then it inserts the contents of n-th parentheses, more about it in the chapter Capturing groups
$<name> inserts the contents of the parentheses with the given name, more about it in the chapter Capturing groups
$$ inserts character $

$&를 사용한 예시를 살펴봅시다.

alert( "I love HTML".replace(/HTML/, "$& and JavaScript") ); // I love HTML and JavaScript

regexp.test로 일치 여부 확인하기

패턴과 일치하는 부분 문자열이 하나라도 있는 경우 메서드 regexp.test(str)을 호출하면 true가, 그렇지 않으면 false가 반환됩니다.

let str = "I love JavaScript";
let regexp = /LOVE/i;

alert( regexp.test(str) ); // true

지금까지 살펴본 내용은 기본에 불과합니다. 이제 이어지는 챕터들에선 더 많은 정규 표현식과 예시들, 메서드들을 살펴보도록 하겠습니다.

메서드들에 대한 정보는 Methods of RegExp and String에서 확인할 수 있으니 참고 바랍니다.

요약

  • 정규 표현식은 패턴과 선택적으로 사용할 수 있는 플래그 g, i, m, u, s, y로 구성됩니다.
  • 플래그와 특수 기호(추후 학습)가 없는 경우엔 일반적인 부분 문자열 검색과 동일한 방식으로 검색이 진행됩니다.
  • 플래그 g가 있는 경우엔 str.match(regexp)는 패턴과 일치하는 모든 부분 문자열을 검색합니다. g가 없는 경우엔 첫 번째 부분 문자열만 찾습니다.
  • str.replace(regexp, replacement)regexp과 일치하는 부분 문자열을 replacement로 교체합니다. g 플래그가 있으면 부분 문자열 전체를, 없으면 첫 번째 부분 문자열을 교체합니다.
  • 패턴과 일치하는 부분 문자열이 하나라도 있는 경우 regexp.test(str)true를 반환합니다. 그렇지 않으면 false가 반환됩니다.
튜토리얼 지도

댓글

댓글을 달기 전에 마우스를 올렸을 때 나타나는 글을 먼저 읽어주세요.
  • 추가 코멘트, 질문 및 답변을 자유롭게 남겨주세요. 개선해야 할 것이 있다면 댓글 대신 이슈를 만들어주세요.
  • 잘 이해되지 않는 부분은 구체적으로 언급해주세요.
  • 댓글에 한 줄짜리 코드를 삽입하고 싶다면 <code> 태그를, 여러 줄로 구성된 코드를 삽입하고 싶다면 <pre> 태그를 이용하세요. 10줄 이상의 코드는 plnkr, JSBin, codepen 등의 샌드박스를 사용하세요.