R Separate name string based on all caps versus normal case

Viewed 51

I have a list of full name, where the last name is all caps, the first name is normal case. I would like to separate this into last name and first name using the separate function. I'm not great at regex, though tried a few things, none quite right. Here is a sample:

my_column_of_names <- c("DI VICENZO John", "SMITH Anne Marie", "O'ROURKE Paddy", "MARTIN-JONES Jim Rae")

Any thoughts are appreciated.

1 Answers

How about this, using tidyr's function extract:

library(tidyr)
library(dplyr)
data.frame(my_column_of_names) %>%
  extract(my_column_of_names,
          into = c("Family", "First"),
          regex = "([A-Z\\s'-]+(?![a-z]))[,\\s]+(.*)")
        Family      First
1   DI VICENZO       John
2        SMITH Anne Marie
3     O'ROURKE      Paddy
4 MARTIN-JONES    Jim Rae

How the regex works:

Essentially we divide the strings into two capturing groups, one for Familiy names, one for First names; what's in between them is 'mentioned' in regex but not captured and therefore not extracted:

  • ([A-Z\\s'-]+(?![a-z])): the 1st capture group, matching any upper-case letters, whitespaces, hyphens, and apostrophes occurring one or more times unless the immediately next character is lower-case (this restriction is expressed in the negative lookahead (?![a-z]))
  • [,\\s]+: a comma or/and whitespace occurring one or more times
  • (.*): the 2nd capture group, which matches anything after the prior

EDIT:

Here's how tidyr's function separate would do the job:

data.frame(my_column_of_names) %>%
  separate(my_column_of_names,
          into = c("Family", "First"),
          sep = "(?<=[A-Z][A-Z])\\s+(?=[A-Z][a-z])|,\\s")

Unlike extract, which works by describing the string in full and separating the bits of interest with capture groups, separate works by defining a splitting point. In the present case, that takes a bit of regex syntax:

Here we define two alternative splitting points:

  • (?<=[A-Z][A-Z])\\s+(?=[A-Z][a-z]): first splitting point - a whitespace occurring one or more times that is (i) preceded by two upper-case letters and (ii) followed by one upper-case and one lower-case letter
  • |: alternation marker
  • ,\\s: second splitting point - a simple comma followed by whitespace
Related