본문 바로가기
시리즈/자바

[JAVA] 몰라서 못 썼던 정규 표현식을 알아보자 ②

by 되고싶은노력가 2024. 10. 20.

[ 정규표현식 시리즈 ]

몰라서 못 썼던 정규 표현식을 알아보자 ①

몰라서 못 썼던 정규 표현식을 알아보자 ②

몰라서 못 썼던 정규 표현식을 알아보자 ③

몰라서 못 썼던 정규 표현식을 알아보자 ④

 


 

기능적으로는 앞서 작성했던 세 가지 연산(집합, 선택, 반복)만으로도 할 수 있지만 가독성을 위해 추가된 표현식에 대해 적어보겠습니다.

 

# 수량자

는 특정한 패턴을 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은 그 사이 빨간색 점선을 표기한 것입니다. 즉, 문자가 아닌 위치에 일치하는 모습을 볼 수 있습니다.

 

이 위치 정규 표현식이 왜 필요한지는 문자열 치환에 작용하는데 다음 포스팅에 정리하도록 하겠습니다.

 

 


참고 자료

https://kasterra.github.io/regex2-syntax-sugar-and-etc/