# A tibble: 5 × 3
name sex total
<chr> <chr> <int>
1 Sunshine F 4959
2 Shineka F 150
3 Shine F 95
4 Shine M 44
5 Sunshine M 37
Thursday, June 18, 2026
Today: Thursday June 18
Before class
Plan for today
., character classes [ ], alternation |? * + {n}, anchors ^ $, and escaping( ) and pulling pieces outHelpful links
A regular expression (regex) is a compact way to describe a pattern in text. Lots of everyday strings follow patterns:
| Kind | Examples |
|---|---|
| Phone numbers | (651) 696-6000 · +1 651.696.6000 |
| Times | 10:30 AM · 13:15.54 |
| Durations | 1:59:40 (Kipchoge’s sub-2-hour marathon) |
| US postal codes | 16801 · 55105-1362 |
| Stray whitespace | " henry " |
A regex lets you say “match anything that has this particular shape” without having to list out every possible case (which is often impossible).
Across all of data cleaning, regex does three things:
| Job | base R | stringr (tidyverse) | Often with |
|---|---|---|---|
| Detect a pattern | grepl() |
str_detect() |
filter() |
| Replace a pattern | gsub() |
str_replace_all() |
mutate() |
| Extract a match | regmatches() |
str_extract() |
mutate() |
The textbook uses base R (grepl, gsub); the analogous versions from the stringr package do the same things but have tidier names.
grepl(pattern, x) returns TRUE/FALSE for each string. The pattern is the quoted string. Here: names containing “shine” (ignore.case = TRUE ignores capitalization):
# A tibble: 5 × 3
name sex total
<chr> <chr> <int>
1 Sunshine F 4959
2 Shineka F 150
3 Shine F 95
4 Shine M 44
5 Sunshine M 37
str_detect(name, regex("shine", ignore_case = TRUE)) does the same thing.
The simplest patterns are literal: "able" matches any string containing “able” (“capable”, “tabled”) but is case-sensitive by default (“Able” won’t match unless ignore.case = TRUE).
These characters are special in that they mean something other than themselves:
For example . means “any single character”, so ".ble" matches “able”, “soluble”, “fungible”, “Bible”.
| Character | Meaning | Example |
|---|---|---|
. |
Any single character (except a newline) | ".ble" matches “able”, “soluble”, or “Bible”. |
^ |
Start of the string | "^a" matches “apple” but not “banana”. |
$ |
End of the string | "e$" matches “apple” but not “elephant”. |
[ ] |
Character class (matches any one character inside) | "[ab]c" matches “ac” or “bc”. |
| |
OR (alternation) | "cat|dog" matches “cat” or “dog”. |
( ) |
Grouping (treats multiple characters as one unit) | "(ab)+" matches “abab”. |
* |
Zero or more of the preceding item | "a*b" matches “b”, “ab”, or “aab”. |
+ |
One or more of the preceding item | "a+b" matches “ab” or “aab” (but not “b”). |
? |
Zero or one of the preceding item (makes it optional) | "colou?r" matches “color” or “colour”. |
{ } |
Quantifier (specific number or range of repetitions) | "a{2,3}" matches “aa” or “aaa”. |
Note: If you ever need to match one of these special characters literally (like an actual period or question mark), you have to escape it by putting a backslash in front of it (e.g.,
\.or\?). In R, because of how strings work, you usually need two backslashes (e.g.,\\.).
[ ]Square brackets mean “any one of these characters”:
[aeiou] \(\rightarrow\) any vowel[^aeiou] \(\rightarrow\) not a vowel (the ^ inside brackets means “except”) \(\rightarrow\) a consonant[0-9] \(\rightarrow\) any digit; [a-z] \(\rightarrow\) any lowercase letter# A tibble: 3 × 3
name sex total
<chr> <chr> <int>
1 Autumn F 104408
2 Sumner M 2287
3 Amna F 1099
Tip
A vertical bar | means “or”: "rain|snow|sleet|hail" matches any of those four words.
Two patterns side by side means “this then that”. ^[^aeiou].[^aeiou].[^aeiou] reads as:
^ start of string, then[^aeiou] a consonant, . anything, [^aeiou] a consonant, . anything, [^aeiou] a consonanti.e. the 1st, 3rd, and 5th letters are consonants:
A quantifier follows a pattern and says how many times it repeats:
| Quantifier | Means |
|---|---|
? |
zero or one time |
* |
zero or more times |
+ |
one or more times |
{n} |
exactly n times |
{n,m} |
between n and m times |
{n,} |
n or more times |
Warning
The Data Computing reading swaps the definitions of + and *. In R (and every real regex engine): * = zero-or-more, + = one-or-more.
[1] "Miss" "Man" "Miocene"
[1] "Mr." "Ms" "Mrs." "Miss" "Man" "Miocene"
Three or more vowels in a row, [aeiou]{3,}:
^ and end $Outside of square brackets, ^ and $ are anchors:
^ = the start of the string$ = the end of the stringNames that end in a vowel, [aeiou]$:
# A tibble: 2 × 2
sex total
<chr> <int>
1 F 96702371
2 M 21054791
Girls’ names end in a vowel almost five times as often as boys’ names.
To match a special character literally, escape it with \\. So \\. means a real period, and \\$ a real dollar sign (not the end-of-string anchor).
[1] "100.95" "45"
Here ^\\$ is a literal $ at the start; ¢$ is a literal ¢ at the end. Without the \\, that first $ would mean “end of string”.
Wrap part of a pattern in ( ) to capture it; in other words, pull that piece out. str_extract() returns the matched text; with capture groups, gsub() can refer back to group 1 as \\1.
Names with four vowels in a row, extracting those vowels:
# A tibble: 4 × 3
name total match
<chr> <int> <chr>
1 Louie 29293 ouie
2 Sequoia 3275 uoia
3 Gioia 480 ioia
4 Keiaira 81 eiai
\\1The regex ".*([aeiou])$" = “anything, then a captured final vowel”. In gsub(), replacement = "\\1" keeps only the captured group, so the whole name collapses to its last vowel:
# A tibble: 5 × 3
vowel F M
<chr> <int> <int>
1 a 56088501 1844041
2 e 36432218 14341114
3 i 3693024 753311
4 o 403120 4041190
5 u 85508 75135
Names ending in “a”, “e”, “i” skew female; “o” skews male.
Scraped numbers arrive with $, ,, %, units. A character class lists everything to delete at once:
# A tibble: 3 × 3
country debt percGDP
<chr> <chr> <chr>
1 World "56308 " 64
2 United States* "17607 " 73.60
3 Japan "9872 " 214.30
[$,%] deletes any $, ,, or %; |billion also deletes the word “billion”.
^ +| +$ matches one-or-more spaces at the start or the end:
Tip
stringr has friendly shortcuts for these: str_remove_all(), str_trim() (ends), and str_squish() (ends + collapse internal runs). Same regex ideas underneath.
Open day23-activity.R in RStudio and work through the parts in order. (Work on the activity when it isn’t your group’s turn for oral check-in #1.)
grepl() / str_detect() + filter() on BabyNames.gsub().What we covered
. any char · [aeiou] class · [^aeiou] negation · | or? * + {n} {n,m} {n,} (R: + = one-or-more, * = zero-or-more)^ start, $ end; escape specials with \\( ); pull pieces with str_extract() or \\1 in gsub()gsub() (or str_remove_all/str_squish)Upcoming
Reach out
Stuck? Office hours, or email me (cgc5478@psu.edu) or Xinyue (xpw5228@psu.edu).
Reference
Syllabus · AI policy · Schedule · DC Ch. 17 · regex101.com