How to Use 'substring' Function in R

R Published Updated 2 mins read By Leon Wei
How to Use 'substring' Function in R cover image

Quick summary

Summarize this blog with AI

Introduction

substring() selects characters by one-based, inclusive positions. It is appropriate for a known fixed layout. Assigning through substring replaces existing character positions; it does not expand a five-character field into a longer word. Use pattern replacement or reconstruction when the string length must change.

Tested with R 4.5.1. Run the following code blocks in order. All inputs are included.

Extract a fixed-width field

The start and end positions both belong to the result. Omitting the end takes the rest of the string.

text <- "Hello, World!"
print(substring(text, 8, 12))  # "World"
print(substring(text, 8))      # "World!"
stopifnot(identical(substring(text, 8, 12), "World"))
fields <- c("2026-01-15", "2026-12-03", NA_character_)
months <- substring(fields, 6, 7)
stopifnot(identical(months, c("01", "12", NA_character_)))

Extracting positions 6–7 does not validate a date. Parse and validate dates with an explicit date format when calendar validity matters; fixed slices alone accept impossible months.

Understand replacement width

The replacement is limited by the selected region and existing string. Compare a fixed-width replacement with a length-changing operation.

fixed_width <- text
substring(fixed_width, 8, 12) <- "Universe"
print(fixed_width)  # "Hello, Unive!"
stopifnot(identical(fixed_width, "Hello, Unive!"))
expanded <- sub("World", "Universe", text, fixed = TRUE)
print(expanded)     # "Hello, Universe!"
stopifnot(identical(expanded, "Hello, Universe!"))

The truncation is normal substring replacement behavior, not a successful insertion of the whole replacement word. For repeated replacement throughout text, see gsub examples.

Find variable-width fields by their pattern

Hard-coded log positions break when prefixes change. Extract the matched error-code field first, then remove its fixed label.

logs <- c("[ERROR] Error code 500", "Error code 404", "Task complete", NA_character_)
pattern <- "Error code [0-9]{3}"
found <- regexpr(pattern, logs)
code <- rep(NA_character_, length(logs))
has_match <- !is.na(logs) & found > 0
field <- regmatches(logs[has_match], regexpr(pattern, logs[has_match]))
code[has_match] <- substring(field, nchar("Error code ") + 1L)
print(code)  # "500" "404" NA NA
stopifnot(identical(code, c("500", "404", NA_character_, NA_character_)))

This pattern is for the demonstrated log contract, not every possible log format. Missing and unmatched records keep their positions. For a reliable structured logging pipeline, prefer explicit fields to parsing human-readable messages.

Check vector and boundary behavior

substring can recycle argument vectors; choose lengths deliberately. On ordinary UTF-8 text it counts characters, not user-perceived grapheme clusters.

texts <- c("alpha", "bravo")
print(substring(texts, c(1, 2), c(2, 4)))  # "al" "rav"
stopifnot(identical(substring(texts, c(1, 2), c(2, 4)), c("al", "rav")))
stopifnot(identical(substring("abc", 5, 7), ""))
stopifnot(identical(substring("abc", 3, 2), ""))
stopifnot(identical(substring("", 1, 3), ""))
stopifnot(is.na(substring(NA_character_, 1, 3)))
stopifnot(length(substring(character(0), 1, 3)) == 0)
stopifnot(identical(substring(enc2utf8("café"), 4, 4), "é"))

A visually single symbol may contain multiple Unicode code points. Do not use byte positions from a different encoding as character positions. Validate format and lengths before applying a fixed-width rule to a new data source.

Primary references

Interview Prep

Begin Your SQL, Python, and R Journey

Master 230 interview-style coding questions and build the data skills needed for analyst, scientist, and engineering roles.

Related Articles

All Articles