😶‍🌫️

[JS] 정규 표현식(Regular Expressions) - 2


정규 표현식(Regular Expressions)

매칭과 그룹

정규 표현식에는 exec 메서드도 존재한다. test가 패턴과 일치하는지 여부만 알 수 있었다면, exec는 매칭에 대한 정보가 포함된 객체를 반환해준다.

1let match = /\d+/.exec("one two 100");
2console.log(match);
3// -> ["100"]
4console.log(match.index);
5// -> 8

리턴받은 객체의 index 속성으로 문자열에서 매칭이 시작되는 위치를 알 수 있다. 리턴받은 객체는 배열에 담겨서 온다. 배열의 첫 번째 요소는 매칭된 문자열이다.

정규 표현식에 괄호로 묶인 하위 표현식이 포함된 경우, 해당 그룹과 매칭되는 텍스트도 배열에서 확인할 수 있다.

1let quotedText = /'[^']*'/;
2console.log(quotedText.exec("She said 'hello'"));
3// -> ["'hello'", "hello"]

하위 표현식이 발견되지 않으면 undefined가 반환되고, 여러번 매칭되면 마지막에 매칭된 놈만 배열로 넘어온다.

1console.log(/bad(ly)?/.exec("bad"));
2// -> ["bad", undefined]
3console.log(/(\d)+/.exec("123"));
4// -> ["123", "3"]

단어와 문자열 경계 지정

문자열 경계는 전체 문자열의 위치(시작이나 마지막 부분)를 기반으로 위치를 찾는다. ^(캐럿)으로 문자열의 시작을, $(달러)로 문자열의 끝을 지정할 수 있다.

예를 들어, /^A/ 는 "an A" 의 'A'와는 대응되지 않지만, "An E" 의 'A'과는 대응된다.

\b로는 단어 경계를 지정할 수 있다. 여기서 말하는 단어 경계란 문자열에서 어느 한쪽은 word character(\w)이고 다른 쪽은 non-word character인 지점을 뜻한다.

예를 들어, /\bm/는 "moon"의 'm'에 대응된다. 'm' 앞이 단어의 경계이기 때문이다. /oo\b/ 는 "moon"의 'oo' 부분에 대응되지 않는다. 왜냐하면 'oo'를 뒤따라오는 'n'이 단어 문자여서 단어의 경계가 아니기 때문이다.

선택 패턴

파이프 문자(|)는 파이프 문자 기준 왼쪽과 오른쪽 패턴 사이의 선택을 나타낸다.

1let animalCount = /\b\d+ (pig|cow|chicken)?s\b/;
2console.log(animalCount.test("15 pigs"));
3// -> true
4console.log(animalCount.test("15 pigchickens"));
5// -> false

백트래킹

정규 표현식 /\b([01]+b|[\da-f]+h|\d+)/는 이진수와 b, 16진수와 h, 일반적인 10진수와 매칭된다. 여기에 "103"을 매칭시키면 어떤 방식으로 동작하는 걸까?

일단 이진수인지 확인이 시작된다. 확인하다가 '3'을 만나면 "아 이진수가 아니네;"라고 인식하고 백트래킹을 한다. 그리고 다음인 16진수인지 확인을 하지만 끝에 'h'가 없기 때문에 또한 실패한다. 그 다음에 10진수인 것을 확인하게 된다.

이렇게 맞는 것을 찾을 때까지 백트래킹이 이루어진다.

백트래킹 때문에 성능에서 극심한 손해를 볼 수도 있다. 예로 /([01]+)+b/를 보자.
0과 1로만 이루어진 문자열을 줬을 때, 일단 0과 1인 것을 쭈욱 비교해서 맞다는 것을 알게된다. 그 다음에 매칭하려고 보니 'b'가 빠진 것을 알아차리게 된다. 그러면 한 칸 백트래킹을 한 후 b가 있는지 확인을 한다. 당연히 b는 없기 때문에 결국 처음으로 돌아올 때까지 계속 백트래킹을 하게 된다.

즉, 정규 표현식을 어떻게 작성하냐에 따라 성능차이가 클 수 있다.

그러니 정규 표현식을 사용할 때, 무지성으로 막 사용하지 말자...!

참조:
Eloquent JavaScript
https://developer.mozilla.org/ko/docs/Web/JavaScript/Guide/Regular_Expressions#special-word-boundary