An introduction to stringr
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.
- you don’t need anything apart from an R setup for this session
- you might like to use this set of interesting words generated by blended LLM and KIND member labour if you’re looking for some play data to try some of these ideas out
- you’ll almost certainly want the stringr cheatsheet on hand
Setup
Create a new project, attach the stringr and dplyr packages, and create some simple data:
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 againIf 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 suspiciousSubsetting
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
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 5There’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