stringr str_trim() in R: Trim Whitespace From Strings
stringr str_trim() removes leading and trailing whitespace from every element of a character vector. It is vectorised, NA aware, and lets you trim one side or both, which makes it the standard first step when cleaning text scraped from files, forms, or spreadsheets.
str_trim(x) # trim both sides (default) str_trim(" hello ") # returns "hello" str_trim(x, side = "left") # trim leading whitespace only str_trim(x, side = "right") # trim trailing whitespace only str_trim(c(" a ", " b ")) # vectorised over a vector str_trim(NA_character_) # NA stays NA (NA-safe) df |> mutate(name = str_trim(name)) # trim a data frame column str_squish(x) # trim plus collapse inner spaces
Need explanation? Read on for examples and pitfalls.
What str_trim() does in one sentence
str_trim(string, side = "both") returns a copy of the input with whitespace stripped from the start, the end, or both. It works element-wise on a character vector, propagates NA inputs as NA outputs, leaves all internal characters untouched, and recognises spaces, tabs, and newlines as whitespace using the Unicode-aware rules from the underlying stringi engine.
Use str_trim() whenever stray spaces would break a comparison, a join key, or a numeric conversion. It is almost always the first cleanup step before any pattern matching.
The output keeps the original length, NA stays NA, and a string that was all whitespace collapses to the empty string.
Syntax
str_trim(string, side = c("both", "left", "right")) takes two arguments. The first is the character vector to clean; the second selects which end to trim. The default "both" removes whitespace from the start and the end in a single call.
Because str_trim() is vectorised, you can clean thousands of strings in one call without writing a loop.
Only the leading whitespace is removed, so trailing spaces on "right " and "both " survive untouched.
which or side argument. Prefer str_trim() inside tidyverse pipelines for a consistent str_ naming style and reliable NA handling.Five common str_trim() scenarios
Five scenarios cover almost every real use of str_trim(). Each block stands alone so you can paste it into the live console.
Clean a column inside a data frame
Most cleanup happens inside a tidyverse pipeline. Combine str_trim() with mutate() to rewrite a messy column in place.
Every value loses its surrounding spaces, which is essential before you use the column as a join key or a grouping variable.
Fix a comparison broken by stray spaces
A trailing space makes two visually identical strings unequal. Trim both sides before comparing so the test reflects the content, not the formatting.
The first test fails because the left value carries two leading spaces. After str_trim(), the comparison returns TRUE.
Match against a lookup vector
Stray spaces cause %in% to silently miss valid matches. Trim the input before testing membership against a known set.
Without str_trim(), the first two values would return FALSE even though they name real fruit.
Prepare strings for numeric conversion
Numbers pasted from spreadsheets often arrive wrapped in spaces. Trim before converting so the parse is clean and predictable.
Trimming first keeps the conversion explicit and protects you from edge cases where padding interferes with parsing.
Strip whitespace from one side only
Sometimes leading indentation is meaningful and only trailing space is noise. The side argument lets you target exactly one end.
The leading two spaces on the first element are preserved, while the trailing spaces on both lines are removed.
str_trim() vs str_squish() vs trimws()
Three functions look similar but solve different problems. Picking the wrong one usually shows up as leftover internal spaces or inconsistent base R behaviour.
| Function | Source | Trims edges? | Collapses inner spaces? | Best for |
|---|---|---|---|---|
str_trim(x) |
stringr | yes | no | edge whitespace only |
str_squish(x) |
stringr | yes | yes | fully normalised spacing |
trimws(x) |
base R | yes | no | base-only scripts |
Reach for str_trim() when only the leading and trailing whitespace is noise, str_squish() when runs of spaces inside the string also need collapsing, and trimws() when you want to avoid a package dependency.
Common pitfalls
Three pitfalls cause most str_trim() surprises. Each has a one-line fix.
Expecting it to collapse internal whitespace
str_trim() only touches the two ends of the string. Double spaces in the middle of the text survive untouched.
To collapse internal runs of whitespace as well, use str_squish(), which trims the edges and squeezes inner spaces down to one.
Comparing or joining without trimming both sides
Trimming only one value still leaves a case mismatch. The result looks subtly wrong rather than throwing an error.
When you build a join key from text, run str_trim() on both tables before the join so neither side carries hidden padding.
Assuming it strips characters other than whitespace
str_trim() removes whitespace only, never quotes, zeros, or punctuation. Those characters need a pattern-based tool.
To strip a specific leading or trailing character, use str_remove() with an anchored pattern, for example str_remove(x, '^"|"$').
as.factor() or use forcats::fct_relabel(f, str_trim) when you need to keep factor levels.Try it yourself
Try it: The vector c(" Mon ", "Tue ", " Wed") has inconsistent padding. Trim every element and save the cleaned vector to ex_days.
Click to reveal solution
Explanation: str_trim() with the default side = "both" strips whitespace from each end of every element, so all three labels become clean three-letter strings ready for grouping or joining.
Related stringr functions
When str_trim() is not quite what you need, these are the next stops:
- str_squish() trims the edges and also collapses runs of internal whitespace to single spaces.
- str_pad() does the opposite job, adding whitespace to reach a fixed string width.
- str_remove() deletes a pattern from a string, useful for stripping non-whitespace characters.
- str_replace_all() swaps every match of a pattern, for example replacing whitespace with hyphens.
- str_to_lower() lowercases text, a common partner step after trimming during cleanup.
- The full stringr reference documents str_trim() and its arguments.
FAQ
What is the difference between str_trim() and trimws() in R?
Both remove leading and trailing whitespace and return a character vector. str_trim() comes from the stringr package and accepts a side argument of "both", "left", or "right", while base R trimws() uses a which argument with the same three choices. The behaviour is effectively identical, so the choice is mostly about style: use str_trim() inside tidyverse pipelines and trimws() when you want to avoid loading a package.
Does str_trim() remove spaces in the middle of a string?
No. str_trim() only strips whitespace from the start and the end of each string. Internal spaces, including double or triple spaces between words, are left exactly as they are. If you also need to collapse internal runs of whitespace down to a single space, use str_squish() instead, which trims the edges and squeezes the middle in one call.
How do I trim whitespace from a whole column in a data frame?
Use str_trim() inside a dplyr mutate() call: df |> mutate(name = str_trim(name)). Because str_trim() is vectorised, it processes the entire column in one pass without a loop. If the column is a factor, str_trim() returns a character vector, so wrap the result with as.factor() or use forcats::fct_relabel() when you need to keep the factor structure.
Can str_trim() handle tabs and newlines?
Yes. str_trim() treats tabs, newlines, and carriage returns as whitespace, so a string like "\t hello \n" trims down to "hello". It uses Unicode-aware whitespace rules from the stringi engine, which means the behaviour is consistent across Windows, macOS, and Linux rather than depending on the system locale.
What does str_trim() return for an NA value?
str_trim() is NA safe: an NA input produces an NA output, and the length of the result always matches the length of the input. It does not convert NA into the literal string "na". If you need a placeholder instead of NA, replace the missing values before trimming with tidyr::replace_na(x, "") or dplyr::coalesce(x, "").