여러분 안녕하세요. 자바스크립트 정규표현식에서 g 옵션에는 비밀이 숨겨져있다는 것 아시나요?
저는 이 비밀을 알아내기 위해 머리가 깨져버렸답니다.
도저히 모르겠어서 백준에 질문을 드려봤습니다.
그랬더니 어떤분께서 엄청 자세하게 답변을 달아주셨습니다. 정말 감사합니다.
앞으로의 글은 문제답변내용을 공부한 것 입니다.
RegExp에서의 lastIndex란
틀린 원인을 알기 위해 먼저 RegExp(정규 표현식 객체) 의 lastIndex 속성을 알아봅시다. lastIndex 속성은 정규 표현식에서 매칭을 어디까지 했는지를 저장하기 위한 속성이며, 초기 값은 0입니다.
정규 표현식에 전역 플래그를 사용한 경우에 한해,
매칭에 성공하면 매칭에 성공한 문자열의 마지막 인덱스 + 1 값이 저장되며, 실패하면 0 값이 저장됩니다.
> regex = new RegExp('FBI', 'g');
<- /FBI/g
> regex.lastIndex
<- 0
> regex.test('01FBI56');
<- true
> regex.lastIndex
<- 5
틀리는 원인
그렇다면 이제 틀린 원인을 알아봅시다. 앞서 매칭에 성공할 경우 lastIndex의 값이 업데이트된다는 것을 이제 알고 있습니다. 같은 정규 표현식 객체에 대해 매칭을 시도할 경우, lastIndex 에 해당하는 인덱스부터 탐색을 시작한다는 것이 작성하신 코드에서 예상치 못한 다른 결과가 나올 수 있는 원인입니다.
바로바로 lastIndex 가 전역변수처럼 값이 남아있었기 때문이었다.
> regex = new RegExp('FBI', 'g');
<- /FBI/g
> regex.lastIndex
<- 0
> regex.test('I-am-FBI');
<- true
> regex.lastIndex
<- 8
> regex.test('I-am-FBI');
<- false
> regex.lastIndex
<- 0
첫 번째 매칭에서는 lastIndex의 값이 0이므로 당연히 매칭에 성공하여 true가 반환됩니다. 성공했으므로 마지막 문자열인 'I' 문자열의 다음 인덱스인 8이 lastIndex에 저장됩니다.
두 번째 매칭에서는 lastIndex의 값이 8이므로 인덱스가 8인 문자열부터 매칭을 시도합니다만, 이미 인덱스 8은 매칭하고자 하는 문자열의 인덱스 범위를 벗어나므로 매칭이 끝나고, 매칭에 실패하게 됩니다. 그래서 false가 반환됩니다. 실패했으므로 lastIndex의 값은 0이 됩니다.
찾는 것을 실패한 경우 lastIndex가 0이 된다.
해결 방법
- lastIndex가 항상 0이 되도록 유지하거나
- 아예 정규 표현식 객체를 매번 새로 만들어 lastIndex 값이 항상 0을 유지하도록 한다면 해결할 수 있다.
1번
regex.lastIndex = 0;
2번
if (/FBI/g.test(el)) {
result += `${idx + 1} `;
}
Respect
'공부기록 > 자바스크립트 코딩테스트' 카테고리의 다른 글
[백준/JS] 1874 스택 수열 (0) | 2022.06.29 |
---|---|
[백준/JS] 1185 요세푸스 문제 (0) | 2022.06.28 |
[백준/JS] 10845 큐 (0) | 2022.06.28 |
자바스크립트 queue 구현 (0) | 2022.06.28 |
[백준/JS] 2867 FBI (0) | 2022.06.24 |