함정 시리즈

정규 표현식과 하이픈(-)

노새두마리 2024. 5. 6. 23:14

다음은 주어진 문자열로부터 C-, C0, C+, B-, B0, B+, A-, A0, A+를 매칭시키는 코드입니다. 정규 표현식을 활용합니다.

const input = 'A+B-C0';
const scores = input.match(/[ABC][0-+]/g); // ['A+', 'B-', 'C0']

하지만 위의 코드를 실행하면 SyntaxError를 뱉어냅니다.

잘못된 부분은 두 번째 위치의 문자를 매칭하기 위해 사용한 [0-+] 부분입니다.

대괄호에 대하여 간단하게 설명하고 넘어가자면, 대괄호 안에 있는 문자열은 OR처럼 작동하여 해당 위치의 문자가 대괄호 안에 주어진 값들 중 하나인 경우에만 패턴이 일치됨을 나타냅니다.

[ABC]를 예로 들어 설명하면 문자열의 해당 자리가 A, B, C 중 하나일 때 일치됨을 나타냅니다.

이런 대괄호 안에서 하이픈을 두 문자 사이에 사용하게 되면 하이픈 왼쪽의 문자부터 하이픈 오른쪽 문자 사이의 범위를 뜻하는 구문으로 해석됩니다. 코드(숫자)로 변환했을 때 왼쪽 문자의 값 이상 오른쪽 문자의 값 이하인 문자에 대하여 일치한다고 판단합니다.

만약 하이픈(-)을 문자로써 매칭하고 싶다면 두 가지 방법을 사용할 수 있습니다.

  • 하이픈을 대괄호 안의 시작 부분 또는 끝 부분에 위치시킬 것(예: [-ab], [ab-])
  • 하이픈 앞에 이스케이프 문자를 사용할 것(예: [0\-+])

 

어떻게 보면 오류을 발견한 게 행운입니다. 처음 작성한 식의 경우 0(48)이 +(43)보다 큰 값을 가져 Range 관련 오류를 반환하였으나 만약 0과 + 기호의 순서를 반대로 하여 [+-0] 처럼 작성하였다면 왼쪽의 값이 작고 오른쪽 값이 크므로 범위와 관련한 오류없이 +부터 0까지의 범위로 해석되어 +, -, 0 세 가지 문자가 아니라 다음의 문자 모두가 일치되는 경우로 판단되었을 것입니다.

문자 코드
+ 43
, 44
- 45
. 46
/ 47
0 48

 

놀랍게도 +부터 0까지의 범위에 하이픈도 포함되어 있어서 입력이 잘못되지 않는 한 의도한 대로는 동작했겠네요.

위에 제시된 교정 방법 중 이스케이프 문자를 적용해 보고 마치겠습니다.

https://ko.wikipedia.org/wiki/ASCII