人名大写(占'和-)

Decapitalize human names (accounting for ' and -)

我有一个(人)名向量,全部大写:

names <- c("FRIEDRICH SCHILLER", "FRANK O'HARA", "HANS-CHRISTIAN ANDERSEN")

到目前为止,要取消大写(仅首字母大写),我使用的是

simpleDecap <- function(x) {
  s <- strsplit(x, " ")[[1]] 
  paste0(substring(s, 1,1), tolower(substring(s, 2)), collapse=" ")
  }
sapply(names, simpleDecap, USE.NAMES=FALSE)
# [1] "Friedrich Schiller"         "Frank O'hara"         "Hans-christian Andersen"

但我还想考虑 '-。使用 s <- strsplit(x, " |\'|\-")[[1]] 当然可以找到正确的字母,但随后 '- 会丢失。因此,我尝试了

simpleDecap2 <- function(x) {
  for (char in c(" ", "\-", "\'")){
    s <- strsplit(x, char)[[1]] 
    x <-paste0(substring(s, 1,1), tolower(substring(s, 2)), collapse=char)
  } return x
  }

sapply(名称,simpleDecap,USE.NAMES=FALSE)

但这当然更糟,因为结果一个接一个地分开:

sapply(names, simpleDecap2, USE.NAMES=FALSE)
# [1] "Friedrich schiller"      "Frank o'Hara"            "Hans-christian andersen"

我认为正确的做法是根据 s <- strsplit(x, " |\'|\-")[[1]] 拆分,但 paste= 才是问题所在。

这似乎可行,使用 Perl 兼容的正则表达式:

gsub("\b(\w)([\w]+)", "\1\L\2", names, perl = TRUE)

\L 将以下匹配组转换为小写。

虽然我同意 Perl regexp 是更好的解决方案,但 simpleDecap2 方法离工作不远了。

simpleDecap3 <- function(x) {
    x <- tolower(x)
    for (char in c(" ", "-", "'")){
        s <- strsplit(x, char)[[1]] 
        x <-paste0(toupper(substring(s, 1,1)), substring(s, 2), collapse=char)
    } 
    x
}

即把全名转小写,然后将“”、“-”或“'”后的第一个字母转为大写。不如正则表达式好看,而且很可能不如正则表达式那么健壮,但它只需对原始代码进行少量更改即可完成工作。