출시 예정인 정규 표현식 기능

ES2015에서는 유니코드(/u) 및 고정 (/y) 플래그를 사용한 정규 표현식 문법의 상당한 개선사항을 비롯하여 JavaScript 언어에 많은 새로운 기능을 도입했습니다. 하지만 그 이후로 개발은 계속되었습니다. V8팀은 TC39 (ECMAScript 표준 기관)의 다른 회원들과 긴밀하게 협력하여 정규 표현식을 더욱 강력하게 만드는 몇 가지 새로운 기능을 제안하고 공동 설계했습니다.

이러한 기능은 현재 JavaScript 사양에 포함하기 위해 제안되고 있습니다. 제안서가 완전히 수락되지는 않았지만 이미 TC39 프로세스의 3단계에 있습니다. 사양이 완성되기 전에 각 제안서 작성자에게 적시에 설계 및 구현 관련 의견을 제공할 수 있도록 이러한 기능을 플래그 (아래 참고) 뒤에 구현했습니다.

이 블로그 게시물에서는 이러한 흥미로운 미래를 미리 살펴볼 수 있습니다. 다음 예시를 따라하려면 chrome://flags/#enable-javascript-harmony에서 실험용 JavaScript 기능을 사용 설정하세요.

이름이 지정된 캡처

정규 표현식에는 일치하는 텍스트의 일부를 캡처할 수 있는 소위 캡처 (또는 그룹)가 포함될 수 있습니다. 지금까지 개발자는 패턴 내 캡처 위치에 따라 결정되는 색인을 사용하여 이러한 캡처를 참조할 수만 있었습니다.

const pattern = /(\d{4})-(\d{2})-(\d{2})/u;
const result = pattern.exec('2017-07-10');
// result[0] === '2017-07-10'
// result[1] === '2017'
// result[2] === '07'
// result[3] === '10'

하지만 정규 표현식은 이미 읽기, 쓰기, 유지 관리하기가 어렵기로 악명이 높으며 숫자 참조는 더 복잡성을 가중시킬 수 있습니다. 예를 들어 더 긴 패턴에서는 특정 캡처의 색인을 결정하기가 쉽지 않을 수 있습니다.

/(?:(.)(.(?<=[^(])(.)))/  // Index of the last capture?

더 나쁜 점은 패턴을 변경하면 기존의 모든 캡처 색인이 이동할 수 있다는 점입니다.

/(a)(b)(c)\3\2\1/     // A few simple numbered backreferences.
/(.)(a)(b)(c)\4\3\2/  // All need to be updated.

이름이 지정된 캡처는 개발자가 캡처에 이름을 할당하여 이러한 문제를 완화하는 데 도움이 되는 예정된 기능입니다. 구문은 Perl, Java, .Net, Ruby와 유사합니다.

const pattern = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/u;
const result = pattern.exec('2017-07-10');
// result.groups.year === '2017'
// result.groups.month === '07'
// result.groups.day === '10'

이름이 지정된 캡처는 이름이 지정된 역참조 및 String.prototype.replace를 통해 참조할 수도 있습니다.

// Named backreferences.
/(?<LowerCaseX>x)y\k<LowerCaseX>/.test('xyx');  // true

// String replacement.
const pattern = /(?<fst>a)(?<snd>b)/;
'ab'.replace(pattern, '$<snd>$<fst>');                              // 'ba'
'ab'.replace(pattern, (m, p1, p2, o, s, {fst, snd}) => fst + snd);  // 'ba'

이 새로운 기능에 관한 자세한 내용은 사양 제안서를 참고하세요.

dotAll 플래그

기본적으로 정규 표현식의 . 원자는 줄 바꿈 문자를 제외한 모든 문자와 일치합니다.

/foo.bar/u.test('foo\nbar');   // false

제안서에서는 /s 플래그를 통해 사용 설정되는 dotAll 모드를 도입합니다. dotAll 모드에서 .는 줄 바꿈 문자와도 일치합니다.

/foo.bar/su.test('foo\nbar');  // true

이 새로운 기능에 관한 자세한 내용은 사양 제안서를 참고하세요.

유니코드 속성 이스케이프

ES2015에서 유니코드 인식이 도입되면서 숫자로 간주될 수 있는 문자(예: 원이 그려진 숫자 1: ①) 또는 단어 문자로 간주될 수 있는 문자(예: 눈을 나타내는 중국어 문자: 雪)가 갑자기 더 많이 생겼습니다.

둘 다 \d 또는 \w와 일치시킬 수 없습니다. 이러한 약어의 의미를 변경하면 기존 정규 표현식 패턴이 손상됩니다.

대신 새로운 속성 이스케이프 시퀀스가 도입됩니다. /u 플래그로 표시된 유니코드 인식 정규 표현식에만 사용할 수 있습니다.

/\p{Number}/u.test('①');      // true
/\p{Alphabetic}/u.test('雪');  // true

역은 \P로 일치시킬 수 있습니다.

/\P{Number}/u.test('①');      // false
/\P{Alphabetic}/u.test('雪');  // false

유니코드 컨소시엄은 수학 기호나 일본어 가나 문자와 같은 더 많은 속성을 정의합니다.

/^\p{Math}+$/u.test('∛∞∉');                            // true
/^\p{Script_Extensions=Hiragana}+$/u.test('ひらがな');  // true

지원되는 Unicode 속성 클래스의 전체 목록은 현재 사양 제안서에서 확인할 수 있습니다. 자세한 예는 이 유용한 도움말을 참고하세요.

뒤처리 어설션

선행 획 어설션은 처음부터 JavaScript의 정규 표현식 문법의 일부였습니다. 이에 상응하는 뒤처리 어설션이 마침내 도입됩니다. 이 기능은 이미 오래 전부터 V8의 일부였음을 기억하는 분들도 있을 것입니다. ES2015에 지정된 유니코드 플래그를 구현하기 위해 내부적으로 뒤처리 어설션을 사용하기도 합니다.

이름이 이미 의미를 잘 설명합니다. 뒤처리 그룹의 패턴이 앞에 오는 경우에만 일치하도록 패턴을 제한하는 방법을 제공합니다. 일치하는 버전과 일치하지 않는 버전이 있습니다.

/(?<=\$)\d+/.exec('$1 is worth about ¥123');  // ['1']
/(?<!\$)\d+/.exec('$1 is worth about ¥123');  // ['123']

자세한 내용은 뒤로 탐색 어설션에 관한 이전 블로그 게시물과 관련 V8 테스트 사례의 예시를 참고하세요.

감사의 말씀

이 블로그 게시물은 이를 실현하기 위해 노력한 몇몇 사람들을 언급하지 않고는 완성되지 않을 것입니다. 특히 언어 챔피언인 마티아스 바이넨스, 댄 에른버그, 클라우드 파체, 브라이언 털슨, 토마스 우드, 고르켐 야킨, Irregexp 전문가인 에릭 코리는 물론 언어 사양 및 이러한 기능의 V8 구현에 기여한 모든 사람에게 감사의 인사를 전합니다.

새로운 정규식 기능이 마음에 드시기를 바랍니다.