String.prototype.match()와 String.prototype.matchAll() 비교, 캡쳐 그룹(Capture Groups)이란?

slaslaya·2020년 4월 30일
3

String.prototype.match()

문자열에서 정규표현식과 매치되는 부분을 검색한다.

const paragraph = 'Cats are the best';
const regex = /[A-Z]/g;
const found = paragraph.match(regex);

found; // ["C"]

정규식과 매치해서 그 값이 있음 배열로 반환하는거 아닌가? 하고 생각할 수 있는데 match()의 반환값이 다양하기 때문에 간단하게 넘어갈 수 없다.

반환 값

g 플래그에 따른 결과 Array를 반환, 매치되는 결과가 없다면 null를 반환한다.

전역 플래그(global flag) 유무

정규식엔 6가지의 플래그를 사용할 수 있는데 위 예시에서 /[A-Z]/g 마지막에 붙은 g가 플래그이다.
g 플래그는 전역 플래그로 전체 일치하는 모든 결과를 반환한다.
match() 메서드는 g 플래그 유무에 따라 캡쳐 그룹(Capture Group) 유무에 영향을 끼쳐 반환값이 달라진다.

매치된 결과가 있을 때

g 플래그를 사용하고 있다면 정규 표현식과 일치하는 모든 결과를 Array형으로 반환하지만, 캡쳐그룹은 반환하지 않는다.

const str = "Cats are the best. The cat will rule the universe.";
const regexpWithoutE = /\b[a-df-z]+\b/ig;
str.match(regexpWithoutE); // ["Cats", "cat", "will"]

캡쳐그룹이 반환값에 포함되지 않았으며 일치하는 요소가 모두 반환된것을 확인 할 수 있다.
(i 플래그를 사용하면 대소문자를 구분하지 않는다)

g 플래그를 사용하지 않았다면 처음 일치한 값과 캡쳐 그룹을 같이 Array형으로 반환한다.

const str = "Cats are the best. The cat will rule the universe.";
const regexpWithoutE = /\b[a-df-z]+\b/i;
str.match(regexpWithoutE); 
// ["Cats", index: 0, input: "Cats are the best. The cat will rule the universe.", groups: undefined]

g 플래그를 뺐을뿐인데 index, input, groups 3개의 프로퍼티가 생겼고,
처음 일치한 값만 배열에 요소로 반환되었다.

캡쳐링그룹이란?

반환값이 null이 아니거나, g flag를 사용하지 않을 경우 결과값에 추가 프로퍼티가 붙는다.
몇 번째 index에서 매치된 문자열이 나오는지를 나타내는 index와 입력된 원래 문자열을 나타내는 input 그리고 마지막으로 groups이다.

캡쳐 그룹은 괄호를 둘러싼 영역을 말한다.

(?<Name>x)

x에 매치되면 명명된 이름<name>이 key가 되고, 정규식 x에 일치되는 값이 value가 된다.
캡쳐 그룹을 사용하면 패턴 안의 원하는 부분을 편리하게 사용할 수 있다.

let re = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/u;
const result = '2015-01-02'.match(re);
result; 
/* 
[ 
  "2015-01-02", "2015", "01", "02"
  groups: {year: "2015", month: "01", day: "02"},
  index: 0,
  input: "2015-01-02",
  length: 4 
] 
*/

(?<year>\d{4}) 괄호를 둘러싼 영역임을 확인할 수 있으며 (?<Name>x)과 동일하게 사용되었다.

groups: {year: "2015", month: "01", day: "02"}

<Name>year가 key가 되고 정규식과 매치되는 부분이 value가 되었다.

result.groups; // {year: "2015", month: "01", day: "02"}

result.groups.year; // "2015"
result.groups.month; // "01"
result.groups.day; // "02"

이렇게 특정부분에 접근할 수 있다.

String.prototype.matchAll()

캡쳐그룹을 포함하여 정규식에 대한 문자열과 일치하는 모든 결과의 반복자(iterator) object가 반환한다.

let regexp = /고(양)(이(\d?))/g;
let str = '고양이1고양이2';

let array = [...str.matchAll(regexp)];

array[0]; // ["고양이1", "양", "이1", "1", index: 0, input: "고양이1고양이2", groups: undefined]
array[1]; // ["고양이2", "양", "이2", "2", index: 4, input: "고양이1고양이2", groups: undefined]

RegExp 객체는 무조건 /g 플래그를 가져야 하며, 아니면 TypeError 를 던진다. 반환값인 반복자는 재시작 반복이 불가능하다.

for...of, Array.from()와 같이 사용하기

const regexp = /고(양)(이(\d?))/g;
const str = '고양이1고양이2';

const matches = str.matchAll(regexp);

for (const match of matches) {
  console.log(`찾았다 ${match[0]} start=${match.index} end=${match.index + match[0].length}.`);
}
// 찾았다 고양이1 start=0 end=4.
// 찾았다 고양이2 start=4 end=8.

// 재시작 반복이 불가능하다.
// 새로운 반복자를 만들어 matchAll을 다시 호출해야한다.
Array.from(str.matchAll(regexp), m => m[0]);
//  ["고양이1", "고양이2"]

matchAllg 플래그가 없다면 TypeError가 발생한다.

const regexp = RegExp('[a-c]', '');
const str = 'abc';
str.matchAll(regexp); // TypeError

g플래그를 사용했을 때 match() 메서드와 비교

match()메서드와 g플래그를 같이 사용했을 경우

let re = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/g;
const result = '2015-01-02,2015-01-03'.match(re);
result;
// ["2015-01-02", "2015-01-03"]

매치되는 전체를 얻을 순 있지만, index, input, groups 3개의 프로퍼티는 사용할 수 없다.

matchAll()메서드

let re = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/g;
const result = '2015-01-02,2015-01-03'.matchAll(re);
let array = [...result];

array[0];
/*
[
  "2015-01-02" // 완전히 매치
  "2015" // '(?<year>\d{4})' 부분에 의해 매치
  "01" // '(?<month>\d{2})' 부분에 의해 매치
  "02" // '(?<day>\d{2})' 부분에 의해 매치
 groups: {year: "2015", month: "01", day: "02"}
 index: 0
 input: "2015-01-02,2015-01-03"
]
*/

match()와 다르게 index, input, groups 3개의 프로퍼티를 사용할 수 있는걸 확인할 수 있다.

요약

  • match() 메서드는 정규식에 매치되는 값을 배열로 반환한다.
  • match() 메서드의 반환값은 3가지
    1. 아무것도 매치되는게 없다면 null
    2. g 플래그를 사용하지 않고 매치되는 값이 있는경우 단 한개만 배열로 반환된다. index, input, groups 3개의 프로퍼티와 같이 사용할 수 있다.
    3. g플래그를 사용했을 경우 모든 매치된 값을 배열로 반환된다. index, input, groups 3개의 프로퍼티와 같이 사용할 수 없다.
  • 캡쳐그룹은 괄호를 둘러싼 영역을 말한다. (?<Name>x) 캡쳐 그룹을 사용하면 패턴 안의 원하는 부분을 편리하게 사용할 수 있다.
  • matchAll() 메서드는 match() 메서드에서 g플래그와 캡쳐그룹을 같이 사용할 수 없는 점이 보완되었다.
  • matchAll() 메서드는 g 플래그가 없다면 TypeError가 발생한다.

참고

profile
안녕하새요

0개의 댓글