😶‍🌫️

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


정규 표현식(Regular Expressions)

정규 표현식은 문자열 데이터 안의 패턴을 설명할 수 있는 방법이다. 정규 표현식을 처음 보면 암호문 같고 투박해 보여서 멀리하고 싶지만, 한 번 익히고 나면 문자열을 검사하고 처리할 수 있는 강력한 도구가 되어준다. 참고 배워보자.

정규 표현식 만들기

정규 표현식은 객체다. RegExp 생성자를 이용해서 만들거나 슬래시(/)로 패턴을 묶어 만들 수도 있다.

1let re1 = new RegExp("abc");
2let re2 = /abc/;

첫 번째 선언 방식에서는 패턴을 문자열로 작성하기 때문에 백슬래시를 원래 쓰던대로 사용하면 된다.

두 번째 놈은 백슬래시를 다루는 방법이 살짝 다르다.

  • 슬래시(/)를 쓰면 패턴 선언을 끝내버리니까, 패턴안에 슬래시를 포함시키려면 앞에 백슬래시를 놓아야 한다.
  • 특별한 문자 코드(예: \n)의 일부분으로 사용되지 않은 백슬래시는 문자열로 취급되지 않고 패턴의 의미를 바꾼다.
  • 물음표나 더하기 같은 기호는 정규 표현식에서 특별한 의미를 가지기 때문에 앞에 백슬래시를 놓아야 한다.
1let eighteenPlus = /eighteen\+/;

일치 테스트

정규 표현식 객체의 가장 단순한 메서드인 test를 보자. 이 메서드는 문자열을 전달하면, 이 문자열이 표현식의 패턴과 일치하는지 알려준다.

1console.log(/abc/.test("abcde"));
2// -> true
3console.log(/abc/.test("abxde"));
4// -> false

문자 세트

문자열에 abc가 있는지 확인하는 것은 indexOf 호출로도 가능하다. 당연히 정규 표현식은 더 복잡한 패턴을 표현할 수 있다. 안그럼 있는 의미가 없으니...

정규 표현식에서는 대괄호 사이에 문자들을 넣으면, 표현식의 해당 부분에서 대괄호 안에 있는 특정 문자와 매칭한다.

아래 코드는 문자열에 숫자가 포함되어 있는지 확인한다.

1console.log(/[0123456789]/.test("in 1998"));
2// -> true
3console.log(/[0-9]/.test("in 1998"));
4// -> true

여러 공통 문자 그룹에는 고유의 단축 문자가 있다.

  • \d : 모든 숫자
  • \w : 영숫자 (알파벳 + 숫자 + _)
  • \s : 공백 문자 (공백, 탭, 줄 바꿈 등)
  • \D : 숫자가 아님ㅌㅈ
  • \W : 영숫자가 아닌 문자
  • \S : 공백이 아닌 문자
  • . : 개행문자를 제외한 모든 문자

단축 문자를 사용하면 날짜 시간 형식을 아래와 같이 표현할 수 있다. 끔찍하지만...

1let dateTime = /\d\d-\d\d-\d\d\d\d \d\d:\d\d/;
2console.log(dateTime.test("01-30-2003 15:23"));
3// -> true

문자 세트의 반대, 즉 해당 세트의 문자를 제와한 모든 문자를 매칭하려는 경우에는 캐럿(^) 문자를 사용하면 된다.

1let notBinary = /[^01]/;
2console.log(notBinary.test("1100110001"));
3// -> false
4console.log(notBinary.test("1200110001"));
5// -> true

패턴의 부분 반복

지금까지는 한 자릿수를 매칭하는 방법을 살펴봤다. 만약 하나 이상의 연속되는 숫자, 즉 정수를 매칭하려면 어떻게 해야할까?

정규 표현식에서는 어떤 내용 다음 +를 사용하면, 해당 요소가 한 번 이상 반복될 수 있음을 의미한다.

1console.log(/'\d+'/.test("'123'"));
2// -> true
3console.log(/'\d+'/.test("''"));
4// -> false
5console.log(/'\d*'/.test("'123'"));
6// -> true
7console.log(/'\d*'/.test("''"));
8// -> true

*+와 비슷한 의미를 갖지만, 패턴을 0번 매칭하는 것도 허용한다.

?패턴의 일부를 선택사항으로 만든다. 아래 코드를 보면 'u'가 있는 것도 허용하지만, 해당 패턴이 누락된 경우에도 매칭된다.

1let neighbor = /neighbou?r/;
2console.log(neighbor.test("neighbour"));
3// -> true
4console.log(neighbor.test("neighbor"));
5// -> true

패턴을 정확한 횟수만큼 발견하도록 하고 싶다면 중괄호를 사용하면 된다. 예를 들어, 요소 뒤에 {4}를 추가하면 정확히 4번 발견한다. 물론 범위도 지정할 수 있다. {2,4}로 작성하면 요소가 두 번 이상, 최대 네번까지 발견됨을 의미한다. 괄호를 사용할 때 쉼표 뒤에 숫자를 생략하면 제한이 없는 범위를 설정할 수도 있다.

아까 위에서 작성한 끔찍한 날짜 시간 형식 패턴을 좀 더 읽기 쉽게 변환해보자.

1let dateTime = /\d{2}-\d{2}-\d{4} \d{2}:\d{2}/;
2console.log(dateTime.test("01-30-2003 15:23"));
3// -> true

하위 표현식 그룹화

괄호 안에 표현식을 작성하면 괄호 다음에 오는 연산자에 대해서 단일 요소로 계산된다.

1let cartoonCrying = /boo+(hoo+)+/i;
2console.log(cartoonCrying.test("Boohoooohoohooo"));
3// -> true

첫 번째와 두 번째 +는 각각 boohoo에 있는 'o'에만 적용이 되고, 세 번째는 (hoo+)에 적용된다. 첫 번째 줄의 마지막에 있는 i는 정규 표현식이 대소 문자를 구분하지 않게 한다.

참조: Eloquent JavaScript