EthicsComputerCourses
Join training +91 90532 10052

Strings & Regular Expressions

R Programming · Lesson 15 of 29 Intermediate 6 min read Updated

Real data is full of text: names, addresses, phone numbers, product codes, comments. Text values are called strings (or character vectors) in R. You will need to join them, format numbers inside them, cut them apart, and clean messy entries such as "98765-43210" and "+91 99887 76655" into one standard form.

In this lesson you will build and format strings, use the main text functions, and learn regular expressions, a mini-language for describing text patterns.

Joining and formatting text

paste() joins values with a space, paste0() joins them with nothing in between, and sprintf() fills a template:

RTry it yourself
name <- "Ananya"
city <- "Kochi"
paste("Hello", name, "from", city)
paste0("ORD-", 1:3)
paste(c("Tea", "Coffee", "Juice"), collapse = ", ")
sprintf("%s paid Rs %.2f", name, 1299.5)
sprintf("Roll no: %03d", c(7, 42, 115))
sprintf("%-10s|%6.1f", c("Pune", "Lucknow"), c(31.4, 28))
format(1234567, big.mark = ",")
Output
[1] "Hello Ananya from Kochi"
[1] "ORD-1" "ORD-2" "ORD-3"
[1] "Tea, Coffee, Juice"
[1] "Ananya paid Rs 1299.50"
[1] "Roll no: 007" "Roll no: 042" "Roll no: 115"
[1] "Pune      |  31.4" "Lucknow   |  28.0"
[1] "1,234,567"
  • paste() and paste0() are vectorised: paste0("ORD-", 1:3) makes three order numbers.
  • collapse joins all the elements of one vector into a single string.
  • In sprintf(), %s is a placeholder for text, %d for a whole number and %f for a decimal. %.2f means two decimal places, %03d pads with zeros to width 3, %6.1f uses width 6 with one decimal, and %-10s left-aligns text in width 10. Widths line up columns in reports.
  • format() with big.mark adds thousands separators. It groups by threes, so Indian lakh grouping (12,34,567) needs your own code.

Everyday text functions

RTry it yourself
station <- "  New Delhi Railway Station  "
trimws(station)
toupper(trimws(station))
nchar(trimws(station))
substr("Rohtak", 1, 3)
parts <- strsplit("Pune,Kochi,Jaipur", ",")
parts
parts[[1]][2]
startsWith(c("9876543210", "8123456789"), "98")
Output
[1] "New Delhi Railway Station"
[1] "NEW DELHI RAILWAY STATION"
[1] 25
[1] "Roh"
[[1]]
[1] "Pune"   "Kochi"  "Jaipur"

[1] "Kochi"
[1]  TRUE FALSE
FunctionDoes
trimws(x)Removes spaces at the start and end
toupper(x), tolower(x)Changes case
nchar(x)Counts characters
substr(x, start, stop)Cuts out characters by position
strsplit(x, split)Splits text into pieces; returns a list
startsWith(x, prefix), endsWith(x, suffix)Checks the beginning or end

strsplit() returns a list because each input string may split into a different number of pieces. Use [[1]] to get the pieces of the first string.

Regular expressions

A regular expression (regex) describes a pattern instead of fixed text. The search functions grepl(), sub() and gsub() all accept one:

PatternMatches
[0-9]Any one digit
[^0-9]Any one character that is not a digit
[6-9]One digit from 6 to 9
{10}The previous item exactly 10 times
^ and $The start and the end of the text
?The previous item is optional
.Any one character
( )A group, which you can reuse as \\1 in a replacement

Here is a real cleaning job: phone numbers typed in many styles. The goal is ten digits starting with 6 to 9, the pattern used by Indian mobile numbers:

RTry it yourself
phones <- c("98765-43210", "call 9123456780", "12345", "+91 99887 76655")
digits <- gsub("[^0-9]", "", phones)
digits
grepl("^(91)?[6-9][0-9]{9}$", digits)
sub("^91([6-9][0-9]{9})$", "\\1", digits)
Output
[1] "9876543210"   "9123456780"   "12345"        "919988776655"
[1]  TRUE  TRUE FALSE  TRUE
[1] "9876543210" "9123456780" "12345"      "9988776655"
  1. gsub("[^0-9]", "", phones) replaces every non-digit with nothing. (sub() would replace only the first match.)
  2. grepl() returns TRUE where the pattern matches: an optional 91 country code, then a digit from 6 to 9, then nine more digits, with nothing else before or after.
  3. sub() with a group removes a leading 91 only when ten valid digits follow it. \\1 puts back what the brackets matched. A careless sub("^91", "", digits) would also damage "9123456780", a normal number that happens to start with 91.

In R strings, a backslash must be written twice, so the regex \d (a digit) is written "\\d".

Searching and extracting

RTry it yourself
log <- c("Order 1042 paid Rs 450", "Order 1043 paid Rs 1299", "Order 1044 cancelled")
grep("paid", log)
grepv("paid", log)
amounts <- regmatches(log, regexpr("Rs [0-9]+", log))
amounts
as.numeric(sub("Rs ", "", amounts))
grepl("PAID", log, ignore.case = TRUE)
grepl(".", "Rs 450", fixed = TRUE)
Output
[1] 1 2
[1] "Order 1042 paid Rs 450"  "Order 1043 paid Rs 1299"
[1] "Rs 450"  "Rs 1299"
[1]  450 1299
[1]  TRUE  TRUE FALSE
[1] FALSE
  • grep() returns the positions of matching elements, and grepv() returns the matching values.
  • regexpr() finds the first match in each string and regmatches() extracts it. [0-9]+ means "one or more digits".
  • ignore.case = TRUE ignores capital letters.
  • fixed = TRUE treats the pattern as plain text, so . means a real dot, not "any character". Use it whenever you search for text that contains symbols.

Raw strings for paths and patterns

Since R 4.0.0, a raw string r"(...)" keeps backslashes exactly as typed, which is handy for Windows paths and complex regex:

RTry it yourself
path <- r"(C:\Users\priya\data\sales.csv)"
path
writeLines(path)
writeLines("Name:\tMeera\nCity:\tPune")
Output
[1] "C:\\Users\\priya\\data\\sales.csv"
C:\Users\priya\data\sales.csv
Name:	Meera
City:	Pune

When R prints a string, it shows escape sequences, so each backslash appears doubled. writeLines() shows the real text. In a normal string, \t is a tab and \n a new line. In R you can also simply write Windows paths with forward slashes: "C:/Users/priya/data/sales.csv" works too.

Common mistakes

  • Using sub() when you meant gsub(). sub() changes only the first match in each string.
  • Forgetting that . is special in regex. grepl(".", x) matches any character; use fixed = TRUE or "\\.".
  • Single backslashes. "\d" is an error in R; write "\\d" or use a raw string.
  • Forgetting that strsplit() returns a list. Use [[1]] or unlist().

Key points

  • paste(), paste0() and sprintf() build strings; format() adds separators.
  • trimws(), toupper(), nchar(), substr() and strsplit() handle everyday text tasks.
  • grepl() tests, grep()/grepv() find, and sub()/gsub() replace using regular expressions.
  • Anchors ^ and $, classes like [0-9], counts like {10} and groups ( ) describe patterns.
  • Write backslashes twice in normal strings, or use raw strings r"(...)".

Exercise

A college form collected email addresses with messy spacing and capitals: " Priya.S@Example.com ", "rohan@college.ac.in", "kabir at gmail.com" and "MEERA@KOCHI.ORG ". Clean them (trim spaces, convert to lower case), flag which ones look valid with a simple pattern (some characters, @, some characters, a dot, letters), and print each valid address with sprintf() as "OK: address".

Show solution
R
emails <- c("  Priya.S@Example.com ", "rohan@college.ac.in",
            "kabir at gmail.com", "MEERA@KOCHI.ORG  ")
clean <- tolower(trimws(emails))
valid <- grepl("^[^@ ]+@[^@ ]+\\.[a-z]+$", clean)
valid
sprintf("OK: %s", clean[valid])
Output
[1]  TRUE  TRUE FALSE  TRUE
[1] "OK: priya.s@example.com" "OK: rohan@college.ac.in"
[3] "OK: meera@kochi.org"    

[^@ ]+ means "one or more characters that are not @ or a space". The third address has no @, so it fails. Real email validation is more complex; this simple check catches common typing mistakes.

Quick Quiz

1. What does paste0("A", 1:2) return?

2. What is the difference between sub() and gsub()?

3. Which pattern matches text that is exactly six digits?

4. What does sprintf("%.1f", 3.14159) return?

Learn R Programming with a mentor

Free lessons get you started. Our Data Science & Machine Learning training adds real projects and code reviews from working developers.

  • Project-based learning
  • Mentor code reviews
  • Free counselling call