정규표현식을 활용한 문자열 처리

정규표현식의 주요 구성 요소

정규표현식(Regular Expression or Regex)은 특정 패턴의 문자열을 찾거나 변경할 때 사용하는 강력한 도구입니다. 이번 포스팅에서는 정규표현식의 주요 구성 요소와 R에서의 활용법을 간결하고 명확하게 정리해보겠습니다.

문자 클래스(Character Class)

문자 클래스는 특정 문자 집합을 나타낼 때 사용됩니다. 대괄호([]) 안에 문자를 나열하여 문자 집합을 나타낼 수 있습니다. 대괄호에 나열된 문자 중 한 문자와 일치하는지 확인할 때 사용됩니다.

  • 0부터 9까지 숫자 중 한 문자: [0123456789]
  • a부터 z까지 소문자 중 한 문자: [abcdefghijklmnopqrstuvwxyz]
  • 영어 소문자 모음 중 한 문자: [aeiou]

순서가 있는 문자의 경우, 범위를 나타내는 - 기호로 축약하여 나타낼 수 있습니다. 기호 그 자체인 -를 표현하고 싶다면, 대괄호 안에서 문자들 사이가 아닌 처음이나 마지막 위치에 -를 작성하면 됩니다.

  • 0부터 9까지 숫자 중 한 문자: [0-9]
  • a부터 z까지 소문자 중 한 문자: [a-z]
  • 알파벳 중 한 문자: [a-zA-Z]
  • 한글 중 한 문자: [가-힣]

대괄호 안 가장 처음에 ^ 기호로 부정을 표현할 수 있습니다.

  • 숫자가 아닌 한 문자: [^0-9]
  • 숫자, 알파벳, 한글이 아닌 한 문자: [^0-9a-zA-Z]

메타문자(Metacharacter)

문자 클래스로 표기할 경우 길이가 길어지는 경우 메타문자를 사용하기도 합니다. 일반적으로, ‘백슬래쉬 + 알파벳’ 형태로 생겼습니다. ‘백슬래쉬 + 대문자’는 ’백슬래쉬 + 소문자’의 반대 의미로 쓰이므로, ’백슬래쉬 + 소문자’ 의미만 알고 있으면 됩니다.

메타문자 의미 문자 클래스로 표현할 경우
. 줄바꿈 문자(\n)를 제외한 모든 문자 [^\n]
\d 숫자(0-9) [0-9]
\D 숫자가 아닌 문자 [^0-9]
\w 단어 문자(word character), 유니코드에서 글자(letters), 숫자(digits), 언더스코어(underscore)를 의미함 [a-zA-Z가-힣0-9_]
\W 단어 문자가 아닌 문자 [^a-zA-Z가-힣0-9_]
\s 공백 문자(white space), 스페이스 바(``), 줄바꿈(\n), 수평탭 간격 띄우기(\t), 수직탭 간격 띄우기(\v), 프린트 출력 용지 한 페이지 넘김(\f), 동일한 줄 맨 앞으로 커서 이동(\r) 등을 의미함 [\n\t\v\f\r ]
\S 공백 문자가 아닌 문자 [^\n\t\v\f\r ]

수량자(Quantifier)

수량자는 특정 문자의 반복 횟수를 지정하는 데 쓰입니다. 다만, 문자 클래스 안에 수량자를 적으면 문자의 반복 정도가 아니라 기호 그 자체를 나타낸다는 점을 주의해 주세요.

수량자 의미
? 0 또는 1회만 반복
+ 1회 이상 반복
* 0회 이상 반복
{n} n회 반복
{n,} n회 이상 반복
{n, m} n~m회 반복

앵커(Anchor)

앵커는 문자의 특정 위치를 나타내는 기호입니다. 앵커를 사용하면, 문자열의 시작이나 끝과 매칭되는 패턴을 정의할 수 있습니다.

앵커 의미
^ 행의 처음(문자 클래스 안에서 부정을 나타내는 ^와 다른 의미)
$ 행의 끝
\A 텍스트 처음
\Z 텍스트 끝
\b 단어 경계

그룹(Group)

그룹은 ()로 표현하며, 여러 문자를 하나의 단위로 묶는 데 사용됩니다. 연산의 우선순위를 지정하거나 역참조하기 위한 참조 그룹을 정의할 때 쓰입니다.

전후방탐색(Look around)

전후방탐색에서 괄호 안의 문자는 소비되지 않습니다. 즉, 괄호 앞이나 뒤에 있는 문자만 탐색합니다. ‘전방탐색’은 괄호 앞의 문자를 탐색하고, ’후방탐색’은 괄호 뒤의 문자를 탐색합니다. 괄호 안의 문자가 있어야 하는 조건이면 ’긍정형’, 없어야 하는 조건이면 ’부정형’이라고 합니다.

기호가 헷갈릴 수 있는데, 기본 기호는 (?)이고, 긍정형/부정형, 전방탐색/후방탐색에 따라 기호가 추가됩니다. 긍정형은 =, 부정형은 ! 기호가 사용되고, 후방탐색의 경우 ?=/! 사이에 < 기호가 추가됩니다.

전후방탐색 의미
a(?=b) 긍정형 전방탐색: a 다음 b가 나오는 a
a(?!b) 부정형 전방탐색: a 다음 b가 나오지 않는 a
(?<=b)a 긍정형 후방탐색: b 다음 a가 나오는 a
(?<!b)a 부정형 후방탐색: b 다음 a가 나오지 않는 a

백슬래쉬 주의사항

정규표현식에서는 괄호((, )), 중괄호({, }), 대괄호([, ]), 마침표(.), 별표(*), 덧셈기호(+), 백슬래쉬(\) 등이 특별한 의미로 사용됩니다. 특별한 의미로 사용되는 문자를 문자 그 자체를 의미하는 기호로 나타내기 위해서는 앞에 백슬래쉬(\)를 붙여줘야 합니다. 그런데 \\(, \\{, \\.처럼 R에서는 백슬래쉬를 두 번 작성해야 합니다.

R에서의 정규표현식 활용

stringr 패키지

R에서 제공하는 기본 함수도 있지만 stringr 패키지를 사용하면 더 쉽게 문자열을 처리할 수 있습니다. stringr 패키지는 tidyverse에도 포함되어 있어서 tidyverse만 설치해도 됩니다.

stringr 패키지가 제공하는 함수에 정규표현식을 입력하여 문자열을 처리할 수 있습니다. 패턴 일치 여부, 패턴 위치, 패턴 일치 수, 패턴과 일치하는 문자열 일부 추출, 패턴을 포함하는 문자열 추출 등 다양한 작업이 가능합니다. 자세한 내용은 아래 커닝 페이퍼(Cheat sheet)을 참고해 주세요.

경험 상 아래 5개 함수를 주로 사용하게 되는 것 같습니다. 패턴과 일치하는 문자열이 있는지 ’확인(detect)’하거나, 패턴과 일치하는 문자열을 ’추출(extract)’하거나, 다른 문자열로 ’대체(replace)’하는 함수가 활용도가 높습니다. 함수에서 pattern 인자에 문자열 패턴을 정규표현식으로 작성해 주면 됩니다.

함수 설명
str_detect(string, pattern) 각 문자열에서 패턴과 일치하는 문자열이 있는지를 탐색함
str_extract(string, pattern) 각 문자열에서 패턴과 첫 번째로 일치하는 문자열을 추출함
str_extract_all(string, pattern) 각 문자열에서 패턴과 일치하는 모든 문자열을 추출함
str_replace(string, pattern, replacement) 각 문자열에서 패턴과 첫 번째로 일치하는 문자열을 다른 문자열로 바꿈
str_replace_all(string, pattern, replacement) 각 문자열에서 패턴과 일치하는 모든 문자열을 다른 문자열로 바꿈

문자열 유무 감지

str_detect() 함수는 문자열에서 특정 패턴이 존재하는지 여부를 불리언(Boolean) 값으로 변환하는 함수입니다.

# 예시 문자
text <- c("1991년", "2000년", "2010년", "2012년")

# "2000년" 이후에 해당하는지 확인
str_detect(text, "^20")
## [1] FALSE  TRUE  TRUE  TRUE

문자열 추출

str_extract() 함수는 문자열에서 특정 패턴과 첫 번째로 일치하는 문자열을 추출하는 데 사용됩니다.

# 예시 문자
text <- c("이메일 주소는 alice@example.com입니다.", "john.doe@gmail.com도 사용 중이에요.", "다양한 주소들: support@company.com, info@website.or.kr")

# 이메일주소 추출
str_extract(text, "[a-zA-Z_.]+@\\w+\\.[a-zA-Z]+")
## [1] "alice@example.com"   "john.doe@gmail.com"  "support@company.com"

문자열 대체

str_replace() 함수는 문자열에서 특정 패턴과 첫 번째로 일치하는 문자열을 다른 문자열로 대체하는 데 사용됩니다.

# 예시 문자
text <- c("I have an apple.", "She brought apples.", "The apple tree is tall.")

# apple을 orange로 대체
str_replace(text, "apple", "orange")
## [1] "I have an orange."        "She brought oranges."    
## [3] "The orange tree is tall."

이와 같이 정규표현식을 사용하면 복잡한 문자열 처리를 간단하게 수행할 수 있습니다. stringr 패키지와 함께 정규표현식을 활용해 다양한 작업을 시도해 보세요!