An introduction to stringr

R
intermediate
Published

July 28, 2026

About this session

This is a stand-alone beginner/intermediate introduction to using the stringr package in R to manipulate text. It’s pitched somewhere between a complete introduction and a more intermediate skill-builder session, so somewhere between our usual beginner (🌶) and intermediate (🌶🌶) levels. In this session:

  • we’ll introduce stringr and talk about what it’s for
  • we’ll look at a core function toolkit
  • and we’ll compare and contrast to some other ways of working with text in R
  • we won’t try and spend a lot of time thinking about other aspects of text wrangling, or using regular expressions here as we offer other sessions designed to cover that ground

Note that the code examples below are set not to evaluate here. This session, more than most, depends on actually trying the code snippets: it’s definitely worth taking these bits of code and running them yourself, because a bit of puzzling about the output (and what happens when you change it) is needed to get to grips with stringr.

This session also avoids doing any data wrangling. Breaking free text up into words is complicated, and there’s a dedicated session about free text wrangling that covers that material.

TipSession resources

Setup

Create a new project, attach the stringr and dplyr packages, and create some simple data:

library(dplyr)
library(stringr)

fruit <- c("dragonfruit", "elderberry", "fig", "apple", "banana", "currant") # for whatever reason, the stringr cheatsheet uses a vector of fruit names, so we'll keep things interoperable

Detect

str_detect(fruit, "a") # logical output, vectorised, tells you which item contains the pattern

fruit |>
  str_detect("a") # pipe-able, probably best when things get more complicated

str_which(fruit, "a") # index, vectorised

str_detect(fruit, "A") # case sensitive

str_detect(fruit, "(?i)A") # horrid but handy

str_detect(fruit, "rr") # supply string or substring from anywhere in the string

str_starts(fruit, "e") # find strings start that start with the pattern

str_starts(fruit, "e", negate = T) # finds strings that do not start with the pattern

str_ends(fruit, "a|e") # find at end, handy shorthand for several options

str_detect(fruit, ".") # the pattern is really a regex - separate session!

str_count(fruit, "r") # counts occurrences

str_locate(fruit, "r") # note class, and beware: how many times does r occur in "elderberry"?

The naming of things

Stringr sticks to a lovely hierarchical naming convention: everything begins str_, and variant functions are usually named using the _all suffix:

str_locate_all(fruit, "r") # note class again

If you’re working in Rstudio or similar, function autocomplete is a real help: start typing str_ and see what the options are.

A puzzle for you

Given what you already know about stringr, can you write some code to extract all and only the r-containing words from the fruit vector please? You should return that as a new vector, containing just the r-words.

fruit[str_detect(fruit, "r")]
fruit[str_which(fruit, "r")]
fruit[str_detect(fruit, "(?i)r")] # for the suspicious

Subsetting

stringr gives you a shorthand way of doing that o-finding work:

str_subset(fruit, "r") # that is, it's subsetting your original vector

str_extract(fruit, "r") # not very useful with the single letter

str_extract(fruit, ".*rr.*") # much more useful with regular expressions

str_extract_all(fruit, "(?i)[l-n][aeiou]") # bit head-bending

str_view(fruit, "(?i)[l-n][aeiou]") # might be helpful to know about to visualise what's going on with more complicated patterns

str_sub(fruit, start = 1, end = 3) # by character index

str_sub(fruit, start = -2) 

Sorting

str_sort(fruit) # that returns a sorted vector
str_order(fruit) # gets you the indices of a sorted vector
fruit[str_order(fruit)] # equivalent to str_sort(fruit)

Lengths

str_length(fruit) # same as nchar(fruit)

str_trunc(fruit, 6)

str_trunc(fruit, 6, ellipsis = "")

str_pad(fruit, 9, pad = "_", side = "right") 

c("123456789", "1987654321") |> # possibly grubby way of fixing broken CHIs?
  str_pad(10, pad = "0")

c(" space before", "space afterwards ", "double  space") |>
  str_trim()

c(" space before", "space afterwards ", "double  space") |>
  str_squish()

Change

str_to_lower(fruit)
str_to_upper(fruit)
str_to_title(fruit)

str_replace(fruit, "o", "_")
str_replace_all(fruit, "o", "_")

str_c(fruit, " is ", fruit) # beware lengths of vectors
str_flatten(fruit, " and ")

str_glue("Nine squared figs is {9*9} {fruit[3]}s") # basically saves you loading the glue package

tibble(fruit = fruit) |>
  mutate(tiurf =stringi::stri_reverse(fruit)) |>
  str_glue_data("{fruit} backwards is {tiurf}  \n")

str_split(fruit, "a") # splits at each pattern and removes it, returning a list
str_split_i(fruit, "a", i = 2) # split at pattern and return ith match
str_split_fixed(fruit, "a", n = 2) # splits at each match, required n as a max value. Care with the class, and examine row 5

There’s also a weird-but-useful way of modifying substring matches. Note this will alter your fruit vector!

fruit_backup <- fruit
str_sub(fruit, start = 1, end = 3) <- "clonk" # assign into substituted string
fruit
fruit <- fruit_backup # recreate our original vector