매치된 부분을 캡처하기
정규 표현식의 유용함은 검색한 결과를 저장(capture)해 놓고, 이를 이용해서 다른 일을 하고자 할때 빛을 발한다.
매치된 부분 캡처하기(지역, 전역)
정규 표현식의 match()메서드는 일치하는 부분을 찾아내면 캡처된 값들의 배열을 반환하고, 일치하는 부분이 없으면 null을 반환한다.
match()로부터 반환된 배열에는 항상 첫 번째 인덱스에 일치하는 내용 전체가 저장되어 있고, 그 뒤에 캡처된 내용이 순서대로 저장되어 있다.
<script type="text/javascript">
var html = "<div class='test'><b>Hello</b> <i>world!</i></div>";
// 지역 정규 표현식
var results = html.match(/<(\/?)(\w+)([^>]*)>/);
console.log(results[0] == "<div class='test'>"); // 문자열 전체 저장
console.log(results[1] == ""); // 슬래시(/)는 저장되지 않는다.(없으므로)
console.log(results[2] == "div"); // 태그명 저장
console.log(results[3] == " class='test'"); // 속성 저장
// 전역 정규 표현식(/g)
var all = html.match(/<(\/?)(\w+)([^>]*)>/g);
console.log(all[0] == "<div class='test'>");
console.log(all[1] == "<b>");
console.log(all[2] == "</b>");
console.log(all[3] == "<i>");
console.log(all[4] == "</i>");
console.log(all[5] == "</div>");
</script>
g 플래그가 설정된 전역 정규 표현식을 이용하면 match()메서드는 조금 다른 값을 반환한다.
전역 정규 표현식은 지역(local)정규 표현식과 달리 첫 번째 매치되는 문자열만 찾지 않고 모두 매치되는 문자열을 찾는다. 이 때 각 매치 결과 내에 포함된 캡처는 반환하지 않는다.
캡처가 중요한 경우라면 exec() 메서드를 활용하여 전역 정규 표현식을 이용해서 캡처를 사용할 수 있다.
var html = "<div class='test'><b>Hello</b> <i>world!</i></div>"
var tag = /<(\/?)(\w+)([^>]*)>/g, match;
var num = 0;
while((match = tag.exec(html)) !== null){
// 모든 매치는 태그를 하나 갖고, 캡처를 3개 포함
console.log(match.length == 4);
num++;
}
console.log(num == 6); // 여는 태그 3개, 닫는 태그 3개를 찾았다.
반복해서 exec()를 호출한다.
exec() 메서드는 이전 호출에 관련된 상태를 저장하고 있기 때문에, exec()를 호출하면 다음으로 매치되는 부분을 검색한다. 각 호출은 다음으로 매치된 부분과 거기에 포함된 캡처를 반환한다.
정규 표현식 내에서 다시 캡처 참조하기
두 가지 경우 매치에 포함된 캡처를 참조한다.
- 해당 매치내에서 참조하는 경우
- 치환할 문자열 내에서 참조하는 경우
매치 참조
var html = "<b class='test'>Hello</b> <i>world!</i>"
var pattern = /<(\w+)([^>]*)>(.*)<\/\1>/g
var match = pattern.exec(html);
console.log(match[0] == "<b class='test'>Hello</b>");
console.log(match[1] == "b");
console.log(match[2] == " class='test'");
console.log(match[3] == "Hello");
match = pattern.exec(html);
console.log(match[0] == "<i>world!</i>");
console.log(match[1] == "i");
console.log(match[2] == "");
console.log(match[3] == "world!");
\1을 이용해서 정규 표현식 내의 첫 번째 캡처를 참조한다.(태그명, 동일한 태그가 충첩된 것은 포함하지 않음)
치환 참조
replace() 메서드를 호출할 때 호출되는 문자열 내에서 캡처를 참조하는 다른 방법이 있다.
$1, $2, $3 문법을 캡처의 수만큼 이용할 수 있다.
console.log("fontFamily".replace(/([A-Z])/g, "-$1").toLowerCase() == "font-family");
// camel 표기법을 대시(-)를 이용한 표기법으로 변경
$1은 첫 번째 캡처 값을 참조한다. (매치되는 부분을 찾기 전에는 몰랐던 부분을 교체할 문자열에 지정할 수 있도록 해줌)
캡처되지 않는 그룹
괄호() 는 표현식의 그룹과 캡처를 둘다 지정한다. 따라서 괄호로 묶인 부분은 그룹(용어Term을 묶는 역할)인 동시에 캡처로 다룬다.
이 것은 불필요하게 많은 캡처가 만들어지는 결과를 낳을 수 있다. (그룹으로만 사용하고 싶다..!)
var pattern = /((corn-)+)sword/;
"sword"가 나오기전에 "corn-"라는 문자열이 한 번 이상 나오는지 확인하는 정규식이다.
이 정규식에서 괄호로 묶인 부분은 두개이다.
- ("sword" 문자열 앞에 오는 모든 부분을 가리키는)캡처를 지정하는 괄호
- +연산자를 사용하기 위해 "corn-"를 묶은 괄호
정규식은 잘 동작하지만, 내부에 있는 괄호로 인해 의도와는 다르게 하나 이상의 캡처가 만들어진다.
var result = "corn-sword".match(/((corn-)+)sword/);
result[1], result[2] 에 캡처된 "corn-" 문자열이 들어가 있다.
괄호로 묶은 부분에 캡처를 생성하지 않도록 여는 괄호 바로 뒤에 ?: 를 지정하면, 캡처에서 제외를 할 수 있다. (수동적인 하위 표현식(passive subexpression)이라고 함)
var pattern = /((?:corn-)+)sword/;
var result = "corn-sword".match(pattern);
이렇게하면, 바깥에 있는 묶음만이 캡처를 생성한다. 수동적인 하위 표현식이 불필요한 캡처를 방지해 준다.
'프로그래밍 노트 > JAVASCRIPT' 카테고리의 다른 글
[Javascript] ES6 모듈화(import/export) 사용하기 (0) | 2020.12.09 |
---|---|
[Javascript] 함수를 이용해서 치환하기(정규식_5) (0) | 2019.02.25 |
[Javascript] 정규 표현식 컴파일하기(정규식_3) (0) | 2019.01.23 |
[Javascript] 정규 표현식 살펴보기(정규식_2) (0) | 2019.01.21 |
[Javascript] 정규식이 멋진 이유(정규식_1) (0) | 2019.01.21 |