What this quiz covers
This quiz focuses on Cleaning Text Data, giving you a quick way to practice the rules, question types, and explanations that matter most for R Programming.
Two vectors contain names:
first <- c(" Mary Jane ", "Grace ")
last <- c(" Lovelace ", " Hopper")
The values must be joined with |, with no whitespace adjacent to the separator. Internal spaces within a name must be preserved.
Which expression returns c("Mary Jane|Lovelace", "Grace|Hopper")?
trimws(paste(first, last, sep = "|"))paste(trimws(first), trimws(last), sep = "|")paste(trimws(first), trimws(last), sep = " ")gsub(" ", "", paste(first, last, sep = "|"))R Programming Quiz
Practice Cleaning Text Data in R Programming with focused quiz questions that help you check what you know, review explanations, and build confidence with test-style prompts.
This quiz focuses on Cleaning Text Data, giving you a quick way to practice the rules, question types, and explanations that matter most for R Programming.
Try each quiz question before looking at the correct answer. Use the explanations to review missed ideas, then come back to similar questions until the pattern feels familiar.
Two vectors contain names:
first <- c(" Mary Jane ", "Grace ")
last <- c(" Lovelace ", " Hopper")
The values must be joined with |, with no whitespace adjacent to the separator. Internal spaces within a name must be preserved.
Which expression returns c("Mary Jane|Lovelace", "Grace|Hopper")?
trimws(paste(first, last, sep = "|"))paste(trimws(first), trimws(last), sep = "|") (correct answer)paste(trimws(first), trimws(last), sep = " ")gsub(" ", "", paste(first, last, sep = "|"))|.
trimws() strips whitespace from the edges of a string but leaves internal spaces alone. The key insight is that you must trim before pasting, so the separator lands cleanly between already-cleaned strings. That's precisely what B does: trimws(first) produces c("Mary Jane", "Grace"), trimws(last) produces c("Lovelace", "Hopper"), and paste(..., sep = "|") joins them into c("Mary Jane|Lovelace", "Grace|Hopper") — exactly the target output.
A applies trimws() after paste(). By then, the strings look like " Mary Jane | Lovelace " — trimws() only removes the outermost whitespace, so the spaces adjacent to the | separator survive. The result still contains unwanted spaces around the pipe.
C uses sep = " " instead of sep = "|", so the separator is a space rather than a pipe character — the output would be "Mary Jane Lovelace", completely wrong regardless of the trimming.
D uses gsub(" ", "", ...) which removes all spaces everywhere, including the internal space in "Mary Jane" — producing "MaryJane|Lovelace" instead of the desired output.
A reliable rule of thumb: when you need clean separators, trim individual pieces first, then combine — never rely on trimming the final joined string.Consider the value x <- "A---B--C". Each complete run of one or more hyphens must be replaced by a single slash.
Which expression returns "A/B/C"?
gsub("-", "/", x)sub("-+", "/", x)gsub("-+", "/", x) (correct answer)gsub("-+", "/", x, fixed = TRUE)-+), and you need a function that replaces all such groups throughout the string. gsub() does global replacement (every match), while sub() only replaces the first match. The + quantifier means "one or more of the preceding character," so -+ greedily consumes an entire hyphen run as one match.
C uses gsub("-+", "/", x) — the pattern -+ matches --- as one unit and -- as another, replacing each with /, yielding "A/B/C". This is correct.
A fails because gsub("-", "/", x) replaces each individual hyphen separately. The three hyphens between A and B become three slashes, giving "A///B//C" rather than "A/B/C".
B uses sub("-+", "/", x), which has the right pattern but only replaces the first matching run. It correctly collapses --- into / but leaves -- untouched, returning "A/B--C".
D looks like C but adds fixed = TRUE, which tells R to treat the pattern as a literal string, not a regular expression. That means + is no longer a quantifier — R looks for a literal hyphen followed by a literal plus sign, which doesn't exist in x, so nothing gets replaced.
A handy tip: whenever a question involves collapsing runs of characters, mentally check for both + (matches a run) and gsub (replaces all runs).A field contains x <- " # #A ". The cleaning rule is: first remove external whitespace, then remove exactly one leading #, and finally remove any whitespace exposed by that removal.
Which expression returns "#A" while following the stated rule?
trimws(sub("^#", "", x))sub("^#", "", trimws(x))trimws(sub("^#", "", trimws(x))) (correct answer)trimws(gsub("#", "", trimws(x)))x <- " # #A ", the rule specifies three sequential steps: (1) strip external whitespace, (2) remove exactly one leading #, (3) strip any newly exposed whitespace. Option C, trimws(sub("^#", "", trimws(x))), follows this precisely. The inner trimws(x) yields "# #A". Then sub("^#", "", ...) removes the single leading #, giving " #A". Finally, the outer trimws(...) strips that exposed leading space, delivering "#A". ✓
Option A, trimws(sub("^#", "", x)), skips the first trim entirely. sub("^#", "", x) tries to match a leading # on " # #A ", but the string starts with spaces — so no # is removed. You get " # #A" after trimming, not "#A". ✗
Option B, sub("^#", "", trimws(x)), correctly trims first and removes the leading #, producing " #A" — but never applies a final trim, leaving that internal space intact. ✗
Option D uses gsub instead of sub, which removes all # characters, yielding "A" rather than "#A". This violates the "exactly one leading #" rule. ✗
A useful tip: whenever a problem states a multi-step cleaning rule, map each step to a function and nest them inside-out in R — the innermost call runs first.A status vector is defined as x <- c(" pending ", "PENDING review", "not pending"). Only values that equal pending after trimming and ignoring case should be standardized to Pending. Longer phrases must otherwise be preserved, apart from external whitespace.
Which expression implements the rule?
gsub("pending", "Pending", trimws(x), ignore.case = TRUE)ifelse(trimws(x) == "pending", "Pending", trimws(x))ifelse(grepl("pending", x, ignore.case = TRUE), "Pending", trimws(x))ifelse(tolower(trimws(x)) == "pending", "Pending", trimws(x)) (correct answer)"pending" (after trimming whitespace and ignoring case) get replaced. That means "PENDING review" should stay as "PENDING review" (trimmed), not get replaced. The correct approach uses ifelse() to conditionally replace values, combined with tolower(trimws(x)) == "pending" for a case-insensitive exact match. Option D does exactly this: it trims external whitespace, converts to lowercase for comparison, and only replaces exact matches — making " pending " become "Pending" while preserving "PENDING review" as "PENDING review".
Option A is wrong because gsub() performs a substring replacement, not an exact-match replacement. It would turn "PENDING review" into "Pending review", corrupting the longer phrase. Option B is tempting but flawed — it uses == directly on trimws(x), so the comparison is case-sensitive. "PENDING" would not equal "pending", causing missed matches. Option C uses grepl(), which checks for partial containment, not exact equality. This means "PENDING review" would match and incorrectly be replaced with "Pending", losing the longer phrase entirely.
A useful strategy: whenever a rule specifies "only values that equal X," reach for == with appropriate normalization (like tolower() + trimws()), not grepl() or gsub(). Reserve those for partial-match or substitution scenarios. Normalizing both sides of a comparison before checking equality is a clean, reliable pattern in R string processing.Consider the following code:
x <- " Doe, Jane "
sub("^([A-Za-z]+),[ ]+([A-Za-z]+)$", "\\2 \\1", trimws(x))
What value does the expression return?
"Jane Doe" (correct answer)"Doe Jane""2 1""Doe, Jane"trimws(x) strips the leading and trailing whitespace from " Doe, Jane ", producing the clean string "Doe, Jane". That result is then passed to sub().
The pattern ^([A-Za-z]+),[ ]+([A-Za-z]+)$ breaks down as follows: ^ and $ anchor the match to the full string, ([A-Za-z]+) captures the first word (group 1 → "Doe"), ,[ ]+ matches the comma and one or more spaces, and the second ([A-Za-z]+) captures the second word (group 2 → "Jane"). The replacement "\\2 \\1" inserts capture group 2 first, then a space, then group 1 — swapping the names. The result is "Jane Doe", making A correct.
B ("Doe Jane") is wrong because it reflects the original order, not the swapped replacement. You'd get this if you confused \\1 \\2 with \\2 \\1. C ("2 1") is a classic trap — if you forgot that \\1 and \\2 reference capture groups and instead read them as literal backslash-number sequences, you'd expect the numbers to print. In R, \\1 in a replacement string means "insert group 1," not the character 1. D ("Doe, Jane") would occur if trimws() failed or the regex didn't match — but the pattern matches perfectly here.
Your study tip: always trace \\1, \\2 back to their corresponding parenthesized groups in the pattern — the numbering follows left-to-right opening parentheses.The following code cleans a vector and converts cleaned empty strings to missing values:
x <- c(" A ", " ", NA_character_, "B")
y <- trimws(x)
y[!is.na(y) & y == ""] <- NA_character_
What is the resulting value of y?
c("A", "", NA, "B")c("A", NA, NA, "B") (correct answer)c(" A ", NA, NA, "B")c("A", NA, "NA", "B")x <- c(" A ", " ", NA_character_, "B"). When trimws(x) runs, it strips leading and trailing whitespace from every non-NA element. " A " becomes "A", " " (three spaces) becomes "" (an empty string), the NA_character_ stays NA since trimws passes it through unchanged, and "B" stays "B". So after trimming, y is c("A", "", NA, "B").
Next, the assignment y[!is.na(y) & y == ""] <- NA_character_ finds elements that are both non-NA and equal to an empty string, then replaces them with NA. The second element "" satisfies both conditions, so it becomes NA. The third element is already NA, so !is.na(y) is FALSE for it — it's skipped entirely and remains NA. The result is c("A", NA, NA, "B"), confirming B is correct.
Choice A is wrong because it shows "" still in position two — it skips the final replacement step entirely. Choice C is wrong because it shows " A " untrimmed in position one, as if trimws was never applied. Choice D is a tricky distractor: "NA" is a character string, not a true missing value — NA_character_ produces a real NA, not the text "NA".
When you see chained string operations in R, always simulate each line separately before combining them — that's where most mistakes happen.A character vector is cleaned with the following code:
x <- c(" north zone ", "south\t\tzone", " east zone ")
The goal is to remove leading and trailing whitespace and reduce every internal whitespace run to one ordinary space.
Which expression produces c("north zone", "south zone", "east zone")?
stringr::str_trim(x)stringr::str_squish(x) (correct answer)gsub(" ", "", trimws(x))trimws(gsub(" +", "", x))stringr function handles both simultaneously.
str_squish() (choice B) does exactly what the goal describes — it strips leading and trailing whitespace and replaces any internal sequence of whitespace characters (spaces, tabs, newlines) with a single space. Notice that "south\t\tzone" contains tabs, not spaces. str_squish() treats all whitespace characters uniformly, so those tabs become one space, yielding "south zone". That's why B is correct.
Choice A, str_trim(), only removes leading and trailing whitespace. It won't collapse the double tabs inside "south\t\tzone", leaving you with "south\t\tzone" rather than "south zone".
Choice C, gsub(" ", "", trimws(x)), removes all spaces entirely (note the empty replacement string ""), so "north zone" would become "northzone" — the opposite of what you want. It also only targets literal spaces, not tabs.
Choice D, trimws(gsub(" +", "", x)), has the same fundamental flaw: the gsub call deletes all runs of spaces before trimws even gets a chance to act on the edges. You'd again get "northzone", "southzone", etc., plus the tabs still wouldn't be handled.
A useful memory trick: think of str_squish() as "squishing" all whitespace down to a single, neat space everywhere — edges and middle alike. Whenever a question involves tabs or mixed whitespace inside a string, str_squish() is almost certainly the tool you need.A vector contains software versions:
x <- c("v1.2.0", "v10.2", "v1x2")
Every literal period must become a hyphen, while all other characters must remain unchanged.
Which expression produces c("v1-2-0", "v10-2", "v1x2")?
gsub(".", "-", x)sub(".", "-", x, fixed = TRUE)gsub(".", "-", x, fixed = TRUE) (correct answer)gsub("^.$", "-", x)gsub() and sub() in R, the most important distinction to keep in mind is how these functions interpret the pattern argument — as a regular expression by default, or as a literal string when fixed = TRUE.
In regular expressions, a bare period (.) is a wildcard that matches any single character. That's the core trap this question is testing. You need to replace only literal periods, so you must tell R to treat the pattern as a fixed string rather than a regex. That's exactly what gsub(".", "-", x, fixed = TRUE) does — it searches for every literal . and replaces it with -, leaving characters like x untouched. Applied to the vector, this correctly yields c("v1-2-0", "v10-2", "v1x2"), confirming C is right.
Here's why the other options fail: A uses gsub(".", "-", x) without fixed = TRUE, so the . wildcard matches every character — your output would replace all characters with hyphens, not just periods. B uses sub() with fixed = TRUE, which is the right interpretation but the wrong function — sub() replaces only the first match per string, so "v1.2.0" would become "v1-2.0" instead of "v1-2-0". D uses the regex ^.$, which matches strings consisting of exactly one character — none of the strings in x qualify, so nothing gets replaced at all.
A reliable rule of thumb: whenever you want to match a literal special character like ., *, or (, always use fixed = TRUE or escape it as \\. in your regex pattern.A company name is stored as x <- " ACME--West, Inc. ". The cleaning requirement is to delete punctuation, collapse whitespace runs to one space, and remove external whitespace. Hyphens should be deleted rather than converted to spaces.
Which expression returns "ACMEWest Inc"?
stringr::str_squish(gsub("[[:punct:]]+", "", x)) (correct answer)stringr::str_squish(gsub("[[:punct:]]+", " ", x))stringr::str_squish(gsub("[[:alnum:]]+", "", x))stringr::str_trim(gsub("[[:space:]]+", " ", x))x <- " ACME--West, Inc. ", option A applies gsub("[[:punct:]]+", "", x), which removes all punctuation entirely, yielding " ACMEWest Inc. ". The hyphens between "ACME" and "West" vanish, merging those words. Then str_squish() collapses internal whitespace runs and strips leading/trailing spaces, giving the clean "ACMEWest Inc" — exactly what's required.
Option B is the most tempting trap. Using " " (a space) as the replacement instead of "" turns "--" into a space, producing " ACME West, Inc. " after substitution, which after squishing becomes "ACME West Inc" — not the desired result. The comma also becomes a space, and the spec says hyphens should be deleted, not spaced. Option C uses [[:alnum:]]+, which matches letters and digits — the opposite of what you want. It strips out all the actual name content, leaving only punctuation and spaces. Option D never removes punctuation at all; it only collapses whitespace with gsub and trims edges with str_trim, leaving "ACME--West, Inc." intact.
A useful tip: always ask yourself two questions — what pattern am I matching? and what am I replacing it with? Getting either wrong produces a subtly broken result, which is exactly the trap options B and D exploit.