我有一个全名列表,其中姓氏全部大写,名字是正常大小写。我想使用单独的功能将其分为姓氏和名字。我不擅长正则表达式,虽然尝试了一些事情,但没有一件完全正确。下面是一个示例:
my_column_of_names <- c("DI VICENZO John", "SMITH Anne Marie", "O'ROURKE Paddy", "MARTIN-JONES Jim Rae")
任何想法都值得赞赏。
使用tidyr
的函数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
regex
的工作原理:
本质上,我们将字符串分为两个捕获组,一个用于Familiy
名称,一个用于First
名称;它们之间的内容在regex
中被"提及",但未捕获,因此未提取:
([A-Z\s'-]+(?![a-z]))
:第一个捕获组,匹配出现一次或多次的任何大写字母、空格、连字符和撇号,除非紧接下一个字符为小写(此限制在负前瞻(?![a-z])
中表示)[,\s]+
:逗号或/和空格出现一次或多次(.*)
:第二个捕获组,它匹配前一个捕获组之后的任何内容
编辑:
以下是tidyr
的函数separate
如何完成这项工作:
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")
与extract
不同, 的工作原理是完整地描述字符串并使用捕获组分隔感兴趣的位,separate
通过定义拆分点来工作。在本例中,这需要一些正则表达式语法:
在这里,我们定义了两个替代的拆分点:
(?<=[A-Z][A-Z])\s+(?=[A-Z][a-z])
:第一个分割点 - 出现一次或多次的空格,即 (i) 前面有两个大写字母,(ii) 后跟一个大写字母和一个小写字母|
: 交替标记,\s
:第二个分割点 - 一个简单的逗号后跟空格