[ 정규표현식 시리즈 ]
몰라서 못 썼던 정규 표현식을 알아보자 ②
기능적으로는 앞서 작성했던 세 가지 연산(집합, 선택, 반복)만으로도 할 수 있지만 가독성을 위해 추가된 표현식에 대해 적어보겠습니다.
# 수량자
* 는 특정한 패턴을 0회 이상 반복하는 연산자라고 했습니다. 이전 포스트에서 숫자만으로 구성된 길이 1 이상의 문자열을 찾는 정규 표현식은 " (0|1|2|3|4|5|6|7|8|9)(0|1|2|3|4|5|6|7|8|9)* " 와 같이 복잡하게 나타내야하는데 이를 깔끔하게 줄일 수 있는 방법을 수량자를 통해 알려드리겠습니다.
+ (플러스 연산)
+ 패턴은 1회 이상의 반복을 의미합니다. 예를 들어, ab+c 라는 정규 표현식은 ab*c 와 다르게 ac 에는 일치하지 않고 abc, abbbc 에 일치합니다. b가 무조건 반복되어야 하기 때문이죠.
? (물음표 연산)
? 패턴은 0회 또는 1회 반복을 의미합니다. 예를 들어, https?://kasterra.github.io 라는 정규 표현식은 http 와 https 로 시작하는 모든 주소에 일치합니다. s 에만 물음표 연산이 적용되는데 이는 ? 도 반복 연산이기 때문에 우선 순위가 접합 연산보다 높기 때문입니다.
{n, m} (범위 수량자)
{n, m} 은 최소 n 회부터 m 회까지 반복해서 표현하는 연산자입니다. 반복 범위를 기술하기 때문에, 범위 지정 반복 제어 연산이라고도 하며 간단하게 범위 수량자라고도 합니다.
예를 들어 x{1, 5} 라는 표현식은 x가 1회부터 5회까지 반복하는 것을 나타냅니다. 이를 선택 연산으로 풀어 표현하면 x | xx | xxx | xxxx | xxxxx 로 표현할 수 있습니다.
또한 x{3, 3} 처럼 최소 횟수와 최대 횟수를 같은 수로 지정하면 해당 수만큼 반복하며 간단하게 x{3} 으로도 표현할 수 있습니다. 이외에도 x{n, } 처럼 최소 횟수만 치고, 최대 횟수를 생략하면 n 회 이상 반복을 의미합니다.
범위 수량자 사용 시 주의 사항
* 반드시 n 이 m 보다 작거나 같아야 하며, {} 안에는 숫자와 쉼표 이외의 다른 문자가 있어서는 안 됩니다. (공백 포함)
. (임의의 한 문자)
어떤 문자가 올지 모르겠지만 모든 문자를 일치하게 만들고 싶을 때 . 을 사용합니다. 예를 들어 r.*e 라는 정규 표현식은 rare 나 recognize 등 r 로 시작해서 e 끝나는 모든 문자열에 일치합니다.
주의할 점은 . 은 모든 문자에 일치하기 때문에 공백이 있는 문자열에도 일치하며 의도치 않은 동작으로 이어질 수 있습니다. 이를 방지하고 r로 시작하고 e로 끝나는 한 단어만 일치하기 위해서 후술할 문자클래스를 활용합니다.
# 문자 클래스
알파벳이나 숫자 등, 일련의 문자들을 패턴 내에 나타내고 싶을 때에 사용합니다. 문자 클래스에서는 [ ] 안에 표현하고 싶은 문자를 넣으면 되며 예를 들어, 0부터 9까지의 숫자를 나타내기 위해서는 [0123456789] 로 나타낼 수 있습니다.
- (범위 지정)
[0123456789] 와 같이 표현하는 식을 범위 지정 - 을 통해 간략하게 나타낼 수 있습니다. [0-9]로 표현할 수 있으며 숫자만으로 된 길이 1 이상의 문자열을 이제는 [0-9]+ 라는 간단한 형태로 나타낼 수 있습니다.
문자 클래스의 범위 지정은 ASCII 문자 코드의 순서를 따릅니다. [a-Z] 로 범위를 지정하면 알파벳 이외에도 ^ 나 _ 기호 등 6개 기호에 일치하게 됩니다.
^ (부정)
문자 클래스 내에 특정한 문자가 오지 않았으면 사용하는 기호입니다. 예를 들어 [^0-9A-Za-z] 라고 하면, 숫자나 알파벳 외의 문자에 일치하는 정규 표현식이 됩니다. 인용 부호로 감싸진 1개의 문자열에 일치해야 하는 정규 표현식을 만들어야 할 때 주의할 점이 있습니다.
'This is a string'
단순히 '.*' 을 사용하면 되지 않을까라는 생각이 들 수 있지만 이 경우에 쉼표로 분리된 'foo', 'bar' 라는 문자열 2개가 일치하는 경우도 발생하게 됩니다.
이와 같은 상황을 방지하기 위해선 [^'] 을 이용 '[^']' 라는 정규 표현식을 이용하면, 작은 따옴표를 2개만 포함하는 문자열만을 찾게 되므로 'foo'와 'bar'에 각각 일치하게 됩니다.
'troublesome 'case' 와 같이, 이스케이프된 작은 따옴표를 포함하는 문자열도 '([^']|\')* 라는 표현식을 사용하면 '가 아닌 것이나 \' 에 일치하게 되어 올바르게 처리할 수 있게 됩니다.
# 이스케이프
숫자와 문자 이외에 눈에 보이지 않는 스페이스나 탭, 줄바꿈 문자 등의 보이지 않는 문자를 표현하기 위해 사용됩니다. 이를 그대로 정규 표현식에 적용한다면 가독성이 떨어지게 되겠죠. 이런 문자드을 표현하는 수단으로 \ 를 사용하는 이스케이프 방식이 있습니다.
이스케이프 | 의미 | 8진 기법 | 16진 기법 |
\a | 경보문자 | \007 | \x07 |
\f | 페이지 바꿈 | \014 | \x0c |
\t | 수평 탭 | \011 | \x09 |
\n | 줄바꿈 | \012 | \x0a |
\r | 복귀 | \015 | \x0d |
\v | 수직 탭 | \013 | \x0b |
이런 눈에 보이지 않는 문자들 외에 눈에 보이면서 자주 쓰이는 문자들을 간결하게 표현하는 용도로써도 사용되기도 합니다. 예를 들어 [0-9] 는 \d 로 표현되고, [0-9a-zA-Z] 는 \w 로 표현하는 경우입니다. 또 이 방식에서 대문자는 해당 집합의 부정형을 나타냅니다.
이스케이프 | 의미 | 문자 클래스 |
\d | 숫자 | [0-9] |
\D | 숫자 외 | [^0-9] |
\w | 문자열 기호 | [A-Za-z0-9] |
\W | 문자열 기호 외 | [^A-Za-z0-9] |
\s | 스페이스 문자(공백 문자) | [\t\n\f\r] |
\S | 스페이스 문자 외 | [^\t\n\f\r] |
메타 문자를 이스케이프
특수한 용도로 사용되는 메타 문자를 해당 문자 그 자체로 인식 시키는 용도로도 가능합니다. 예를 들어 a*b 는 ab aaab 에 일치하지만 a*b 라는 문자열 자체는 일치하지 않습니다.이를 위해서는 a\*b 처럼 메타문자를 \ 로 이스케이프 시켜줘야합니다.
# 앵커
메타 문자들은 특정한 문자나 문자열에 일치하는 문자였지만, 앵커는 문자열이 아닌, 위치에 일치하는 특이한 메타 문자입니다.
앵커 | 위치 |
^ | 행 처음 |
$ | 행 끝 |
\A | 텍스트 선두 |
\b | 문자열 사이 |
\B | 문자열 사이 외 |
\z | 텍스트 끝 |
위치에 일치한다는게 생소할 수 있습니다. 예를 들어 '문자열과 문자열 사이' 라는 위치에 일치하는 \b 의 예를 들면,
위의 결과에서 초록색으로 되어 있는 것은 (a+ ) 에 일치한 것이고, 파란색으로 되어 있는 부분은 (b+) 에 일치한 부분입니다. \b은 그 사이 빨간색 점선을 표기한 것입니다. 즉, 문자가 아닌 위치에 일치하는 모습을 볼 수 있습니다.
이 위치 정규 표현식이 왜 필요한지는 문자열 치환에 작용하는데 다음 포스팅에 정리하도록 하겠습니다.
참고 자료
'시리즈 > 자바' 카테고리의 다른 글
[TEST] 테스트를 위한 JUnit 5 와 AssertJ ① (1) | 2024.10.24 |
---|---|
[JAVA] 몰라서 못 썼던 정규 표현식을 알아보자 ④ (1) | 2024.10.22 |
[JAVA] 몰라서 못 썼던 정규 표현식을 알아보자 ③ (0) | 2024.10.21 |
[JAVA] 몰라서 못 썼던 정규 표현식을 알아보자 ① (5) | 2024.10.19 |
[JAVA] 직관성있는 자바 네이밍 규칙 (1) | 2024.10.18 |