glue trim() in R: Strip Indentation From Multiline Strings
glue trim() takes a multiline string and removes the leading whitespace shared across every line, plus any empty first or last line. It is the helper that lets you write heredoc-style templates in R source code without the indentation leaking into the rendered output.
trim("\n hello\n world\n") # strip common indent
trim(glue("\n a is {a}\n b is {b}\n")) # post-process a glue() result
glue::trim(string_var) # explicit namespace call
glue("\n multi\n line\n", .trim = TRUE) # glue's built-in equivalent
trim("\nfoo\n bar\n baz\n") # drops empty first/last line
trim(readLines("template.txt")) # multi-element vector input
as.character(trim(x)) # cast back to plain characterNeed explanation? Read on for examples and pitfalls.
What trim() does in one sentence
trim() removes shared leading indentation and empty edge lines from a string so a multiline template in source code renders flush-left. You pass in a string that may have leading newlines, common indentation, or a trailing newline; you get back the same string with all three stripped.
This is not whitespace squeezing. trim() does not touch spaces inside a line, only the indentation common to every non-empty line and any empty first or last line. The result is what a reader would expect from a Python triple-quoted dedent or a shell heredoc.
The two leading spaces shared by both lines disappear, the empty first and last lines disappear, and what remains is two flush-left lines.
Syntax
trim(x) takes one character vector and returns its trimmed form as a glue object. There is only one argument and no separator, width, or last-line option. The function is pure string surgery on whatever you pass it.
The return value is a glue object, which prints without quotes and behaves like a character vector in most contexts. If you need a plain character vector for downstream code that type-checks strictly, wrap the call in as.character().
.trim = TRUE first. glue() already calls trim() on its result when you set .trim = TRUE, which is the default. Use the standalone trim() only when the input did not come from glue(), like a literal heredoc, a sprintf() result, or a chunk read from disk.Common use cases
1. Clean up an indented multiline literal
This is the canonical pattern: write SQL or YAML or prose inline with comfortable indentation, then trim() before sending it anywhere. The two-space indent that made the source readable disappears from the output.
2. Trim the result of a non-glue function
sprintf() does not have a .trim option, so the leading newline and shared indent survive. trim() rescues the output and produces a clean two-line report ready for cat() or writeLines().
3. Compose a multi-step pipeline with the pipe
Here we deliberately turn off glue's internal trim with .trim = FALSE, then re-apply it via the native pipe. The end result is the same as .trim = TRUE, but the two-step form is clearer when the post-glue side also does other string transforms.
4. Build a template once, trim everywhere
Storing the template in a variable separates the layout from the rendering. trim() runs at the point of use, so the same template can be passed to cat(), writeLines(), or knitr without each call having to re-handle the leading indent.
trim() vs trimws() and str_trim()
The three trim functions cover three different jobs, and mixing them up is the most common mistake. trim() handles indentation across a whole multiline block. trimws() handles leading and trailing whitespace per element. str_trim() is the stringr equivalent of trimws() with the same per-element semantics.
| Function | Package | Scope | Removes shared indent? | Removes empty edge lines? |
|---|---|---|---|---|
glue::trim(x) |
glue | The whole multiline block | Yes | Yes |
trimws(x) |
base | Each element of x | No | Only if no other content |
stringr::str_trim(x) |
stringr | Each element of x | No | Only if no other content |
The decision rule: use trim() when the input is one string with embedded newlines and you want flush-left output. Use trimws() or str_trim() when the input is a character vector and you want each element cleaned independently.
Common pitfalls
- Calling trim() on a vector of independent words. trim() treats each vector element as its own string and looks for embedded newlines. If you pass
c(" a", " b ", " c"), you get the same vector back with no per-element trimming, because no element has a leading newline or common indentation across lines. For that, use trimws().
- Forgetting glue() already trims. glue() runs trim() internally when
.trim = TRUE, which is the default. Calling trim() on the result of a default glue() is harmless but redundant. Only reach for the standalone helper when the input did not pass through glue() with default options.
- Mixing tabs and spaces. trim() compares prefixes literally. A line indented with one tab and a sibling indented with four spaces share no common prefix, so trim() leaves both alone. Normalise the indentation in your editor (or run a regex) before relying on trim() to clean things up.
Try it yourself
Try it: Use trim() to clean up the indented ex_letter template below. Save the result to ex_clean and confirm it has two lines starting flush-left.
Click to reveal solution
Explanation: trim() drops the empty first and last lines and strips the two-space leading indent shared by both content lines. The result is two flush-left lines ready for cat() or any downstream consumer.
Related glue functions
glue()interpolates{expressions}into a template, and it calls trim() internally by default; reach for it first whenever the input has variables to substitute.glue_data()is the data-frame counterpart of glue() and inherits the same.trimargument for per-row templates.glue_collapse()joins a character vector into one string; combine it with trim() when the joined result has surrounding whitespace.glue_sql()andglue_safe()are specialised interpolators that also accept.trimfor safe quoting and signature-checked substitution.- See the glue::trim reference for the source and edge-case behaviour.
FAQ
What is the difference between glue trim() and base R trimws()?
trim() operates on the whole string as one multiline block: it strips the indentation shared across every line and drops empty first or last lines. trimws() operates per element of a character vector and strips leading and trailing whitespace from each element independently. Use trim() for cleaning heredoc-style templates and use trimws() for cleaning user input or column values one element at a time.
Does trim() remove internal whitespace?
No. trim() only touches the indentation common to all lines and the first or last line if they are empty. Spaces inside a line, blank lines in the middle of a block, and tabs inside content are all preserved. If you need to squeeze internal whitespace, use gsub("\\s+", " ", x) or a stringr regex such as str_squish().
Why does my glue() output not need trim()?
Because glue() already calls trim() internally when .trim = TRUE, which is the default. The standalone trim() exists for inputs that did not go through glue() with defaults: literal strings, sprintf() output, file reads, or glue() calls where you set .trim = FALSE to defer the cleaning step.
Can trim() handle mixed tab and space indentation?
Only if the indentation is identical on every line. trim() finds the longest prefix shared by all non-empty lines; if some lines start with a tab and others with spaces, the shared prefix is empty and trim() leaves the indentation in place. Normalise the indentation before calling trim().
What does trim() return when the input is empty?
trim() on a zero-length character vector returns a zero-length glue object. trim() on a single empty string "" returns the same empty string. Neither case throws an error, which makes it safe to call on the output of filter pipelines that may legitimately produce no rows.