16  R 문자열과 stringr 패키지

문자열(characteor)은 R에서 텍스트 데이터를 의미하고, 문자열은 작은따옴표나 큰따옴표로 둘러싸서 표현한다. 작은따옴표를 사용하든 큰따옴표를 사용하든 차이는 없다. 다만 작은따옴표 안에 다시 작은따옴표를 바로 쓸 수 없고, 큰따옴표 안에 바로 큰따옴표를 쓸 수는 없다.

mt_name <- "한라산"
mt_name
[1] "한라산"
pt_name <- '홍길동'
pt_name
[1] "홍길동"

base R에는 이런 문자열을 다루는 함수들이 많이 있다. 하지만 함수별로 사용법에 일관성이 없어서 익히기가 어렵다. 그래서 R의 Tidyverse 접근법을 따르는 stringr이라는 패키지는 관련된 함수들을 일관성 있게 정리하여 제공한다. 따라서 R을 처음 배우는 경우라 할지라도 이 패키지를 사용하여 문자열 데이터를 다르는 방법을 배우는 것이 좋을 것으로 생각된다.

이 패키지를 로딩하자.

16.1 인코딩(Encoding)

R 언어에서 문자열은 플레인 텍스트(plain text)로 저장된다. 그런데 이 플레인 텍스트라고 할지라도, 저장하는 알고리즘(인코딩)에 따라 실제로 컴퓨터에 저장되는 방식이 다르다.

인코딩(encoding)이라는 것은 컴퓨터가 문자를 숫자로 바꾸는 방법을 의미한다. 예를 들어서 “A”라는 문자는 65라는 숫자로 저장된다. 이때 “A”라는 문자를 65라는 숫자로 바꾸는 방법이 인코딩이다.

R 4.2.0 버전부터는 윈도우(Windows), 맥오에스(macOS), 리눅스(Linux) 시스템에 상관없이 모두 UTF-8 인코딩을 사용한다. UTF-8은 유니코드(Unicode)라는 국제 표준에 따라 만들어진 인코딩 방식으로, 전 세계의 모든 문자를 표현할 수 있는 인코딩 방식이다.1

Unicode 시스템에서 한글 문자는 국어사전에서 순서에 맞게 배열되어 있으며, 어떤 글자 하나는 하나의 유니코드 코드포인트와 대응하게 된다. 그래서 하나의 글자는 글자 하나로 카운트되고, 문자열끼리 비교도 가능해지고, 이에 따라 정렬도 가능해진다.

"가나다" > "다라마"
[1] FALSE
"가나다" < "다라마"
[1] TRUE

현재 R 세션에서 사용하고 있는 인코딩 방식을 확인하려면 Sys.getlocale() 함수를 사용한다(저자의 컴퓨터는 맥오에스이다).

[1] "en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8"

16.2 정규 표현식(Regular Expression)은 다음 장에서

정규 표현식(Regular Expression, regex)이란 문자열에서 특정한 패턴을 찾기 위해 사용하는 방법으로, 잘 사용하면 아주 간결하면서도 강력한 기능을 제공한다.

stringr 패키지의 많은 함수들을 정규 표현식을 사용하는데, 이것을 사용하려면 정규 표현식을 알아야 하기 때문에, 정규 표현식 관련된 내용은 다음 장으로 넘겨 설명한다.

16.3 문자열 길이

R에서 문자열 데이터는 벡터에 저장된다. 그리고 벡터에 저장된 문자열은 각각의 길이(length)는 모두 1이다. 문자열 자체의 길이를 알려면 base R인 경우 nchar() 함수를 사용하고, stringr 패키지에서는 str_length() 함수를 사용한다.

about_R <- c("R은 자유 소프트웨어이다.", 
             "R은 통계 분석을 위한 프로그래밍 언어이다.", 
             "R은 많은 기여자들이 참여하는 공동프로젝트입니다.")
length(about_R)
[1] 3

다음은 base R nchar() 함수를 사용하였다.

nchar(about_R)
[1] 14 24 27

다음은 stringr 패키지의 str_length() 함수를 사용하였다.

str_length(about_R)
[1] 14 24 27

위와 같이 stringr 패키지의 거의 모든 함수는 str_로 시작한다. 그리고 대부분 벡터화되어 있다.

16.4 문자열 결합

  • stringr 패키지의 str_c() 함수를 사용하여 문자열을 결합할 수 있다. 이때 sep 인자를 사용하여 구분자를 지정할 수 있다.

이 함수는 문자열 벡터를 구성하는 문자열과 문자열을 결합하여 새로운 문자열 벡터를 만든다. 마치 정수형 벡터의 값을 더하는 것과 비슷하다고 생각하면 좋다.

x <- c(1, 3, 5)
y <- c(2, 4, 6)
x + y
[1]  3  7 11
s1 <- c("A", "B", "C")
s2 <- c("1", "2", "3")
str_c(s1, s2)
[1] "A1" "B2" "C3"

이렇게 같은 위치에 있는 요소 대 요소로 묶인다. 위 코드는 이해를 위한 것이고, 다음과 같이 작성해도 같은 방식이라는 것을 이해할 필요가 있다.

str_c(c("A", "B", "C"), 1:3)
[1] "A1" "B2" "C3"

문자열을 결합할 때 사용할 문자를 sep 인자에 지정할 수 있다.

str_c(s1, s2, sep = "-")
[1] "A-1" "B-2" "C-3"
  • str_flatten() 함수는 문자열 벡터의 요소들을 결합하여 하나의 문자열로 만든다.
[1] "ABC"

collapse 인자를 사용하여 구분자를 지정할 수 있다.

str_flatten(s1, collapse = "-")
[1] "A-B-C"
  • str_glue() 함수는 문자열을 결합할 수 있고, 중괄호 {} 안에 R 코드를 넣어 계산한 값을 문자열로 결합시킬 수 있다.
x <- 1
str_glue("A는 {x}입니다.")
A는 1입니다.

다음 예시처럼 str_glue() 함수는 인자로 준 모든 문자열을 결합하면서 {}에 R 표현식을 넣어서 계산한 값을 문자열로 결합할 수 있다.

name <- "Fred"
age <- 50
anniversary <- as.Date("1991-10-12")
str_glue(
  "My name is {name}, ",
  "my age next year is {age + 1}, ",
  "and my anniversary is {format(anniversary, '%A, %B %d, %Y')}."
)
My name is Fred, my age next year is 51, and my anniversary is Saturday, October 12, 1991.

이 문자열에 {}을 문자열로 포함시키고자 한다면 {{}}를 사용하면 된다.

str_glue("My name is {name}, not {{name}}.")
My name is Fred, not {name}.

str_glue() 함수에서 데이터의 값을 인자로 지정해 줄 수도 있다.

str_glue(
  "My name is {name}, ",
  "and my age next year is {age + 1}.",
  name = "Joe",
  age = 40
)
My name is Joe, and my age next year is 41.
  • str_glue_data() 함수는 데이터프레임을 인자로 받아서, 이 데이터프레임에 있는 값을 사용하여 문자열을 만드는 데 사용된다.
library(dplyr)
result_df <- penguins %>%
  group_by(species) %>%
  summarize(avg_mass = mean(body_mass, na.rm = TRUE))
result_df
# A tibble: 3 × 2
  species   avg_mass
  <fct>        <dbl>
1 Adelie       3701.
2 Chinstrap    3733.
3 Gentoo       5076.

result_df 데이터프레임의 species 열의 값과 avg_mass 열의 값을 사용하여 문자열을 만들고자 한다면 다음과 같이 작성한다. 각 행에서 열의 값을 가지고 와서 문자열을 만든다.ㄴ

result_df |> 
  str_glue_data(
    "{species} 종의 평균 체중은 {round(avg_mass/1000, 2)} kg이다."
  )
Adelie 종의 평균 체중은 3.7 kg이다.
Chinstrap 종의 평균 체중은 3.73 kg이다.
Gentoo 종의 평균 체중은 5.08 kg이다.

16.5 공백 제거, 패딩 문자 추가, 말줄임표로 표시

  • str_trim() 함수는 문자열의 앞과 뒤에 있는 공백을 제거한다. side 인자를 사용하여 앞, 뒤, 양쪽 모두를 제거할 수 있다. side 인자의 기본값은 both이다.
str_trim("   Hello World!   ")
[1] "Hello World!"
  • str_squish() 함수는 문자열의 앞과 뒤에 있는 공백을 제거하고, 중간에 있는 여러 개의 공백들도 하나로 줄여준다.
str_squish("   Hello        World!   ")
[1] "Hello World!"
  • str_pad() 함수는 문자의 앞, 뒤, 양쪽에 패딩 문자를 추가한다. width 인자에 지정한 길이만큼 문자열을 만들고, 부족한 부분을 pad 인자로 지정한 문자로 채운다.
str_pad("Hello", width = 10, side = "both", pad = "*")
[1] "**Hello***"
  • str_trunc() 함수는 전체 문자열의 최대 길이를 지정하고, 그 길이를 초과하는 부분은 말줄임표(ellipsis, ...)를 가지는 문자열로 바꾼다.
str_trunc("Hello World! This is a long string.", width = 20)
[1] "Hello World! This..."

공백과 ...(3개)를 합쳐 최대 20개의 문자로 구성된 문자열을 만든다. side 인자로 말줄임표가 어디에 위치할지를 지정할 수 있다. 기본값은 right이다.

16.6 대소문자 변환, 제목 또는 문장 형태 변환

영어에는 대소문자가 있다. 문자열을 대문자, 소문자, 제목 형태로 변환할 수 있는 함수들이 있다.

  • str_to_lower() 함수는 문자열을 소문자로 변환한다.
  • str_to_upper() 함수는 문자열을 대문자로 변환한다.
  • str_to_title() 함수는 문자열을 제목 형태로 변환한다. 제목 형태란 각 단어의 첫 글자를 대문자로 바꾸고 나머지 글자는 소문자로 바꾸는 것이다.
  • str_to_sentence() 함수는 문자열을 문장 형태로 변환한다. 문장 형태란 첫 글자를 대문자로 바꾸고 나머지 글자는 소문자로 바꾸는 것이다.
dog <- "The quick brown dog"
str_to_upper(dog)
[1] "THE QUICK BROWN DOG"
[1] "the quick brown dog"
[1] "The Quick Brown Dog"
str_to_sentence("the quick brown dog")
[1] "The quick brown dog"

16.7 문자열에서 일부 문자열 추출과 수정

  • str_sub() 함수는 문자열에서 위치를 기반으로 일부 문자열을 추출한다. str_sub(string, start=1L, end=-1L) 형태로 사용한다.

    • R에서 인덱스가 1에서 시작하고, 끝도 inclusive 이다.
    • startend는 음수로 지정할 수도 있다. -1은 문자열의 마지막 문자를 의미한다.
about <- "R은 많은 기여자들이 참여하는 공동프로젝트입니다."
str_sub(about, 1, 5)
[1] "R은 많은"
  • str_sub_all() 함수는 복수의 문자열에서 문자열을 추출할 때 사용한다. startend에 벡터를 지정하여, 이 위치 조합에 따라 문자열을 추출할 수도 있다.
x <- c("abcde", "ghifgh")
str_sub_all(x, start = 1, end = 2)
[[1]]
[1] "ab"

[[2]]
[1] "gh"
str_sub_all(x, start = c(1, 2), end = c(2, 4))
[[1]]
[1] "ab"  "bcd"

[[2]]
[1] "gh"  "hif"
  • str_sub() 함수를 할당 <- 좌측에 놓으면, 이 위치에 있는 문자열을 수정할 수 있다.
x <- c("abcde", "ghifgh")
str_sub(x, 1, 2) <- "XY"
x
[1] "XYcde"  "XYifgh"

위치가 아니라 워드 프로세서 등에서 “찾아서 바꾸기”와 같은 기능은 “정규 표현식”을 사용해야 하는데, 이 내용은 다음 장에서 설명한다.

16.8 정리

여기에선 stringr 패키지를 사용한 기본 문자열 처리 방법을 설명하였다. 다음 장에서는 정규 표현식(Regular Expression)을 사용하여 문자열을 처리하는 방법을 설명한다. 정규 표현식은 문자열에서 특정한 패턴을 찾기 위해 사용하는 방법으로, 잘 사용하면 아주 간결하면서도 강력한 기능을 제공한다.


  1. 유니코드와 UTF-8에 대한 자세한 설명은 유니코드(Unicode)UTF-8 문서를 참조하자.↩︎