大写字母。R中类似于Excel的“PROPER”函数。

13

同事们,

我正在查看一个类似于下面提取的数据框:

Month   Provider Items
January CofCom   25
july    CofCom   331
march   vobix    12
May     vobix    0

我希望将每个单词的首字母大写,其余字母小写。这将使数据框看起来像下面这样:

Month   Provider Items
January Cofcom   25
July    Cofcom   331
March   Vobix    12
May     Vobix    0

简而言之,我正在寻找R中类似于MS Excel中可用的ROPER函数的等效函数。ROPER


2
请查看 ?tolower 帮助页面中的 capwords 函数。 - user20650
?tolower 的示例部分中定义了一个 capwords 函数。 - G. Grothendieck
4个回答

32
使用正则表达式:
x <- c('woRd Word', 'Word', 'word words')
gsub("(?<=\\b)([a-z])", "\\U\\1", tolower(x), perl=TRUE)
# [1] "Word Word"  "Word"       "Word Words"

(?<=\\b)([a-z]) 表示查找一个小写字母,其前面有一个单词边界(例如,空格或行的开头)。(?<=...) 被称为“后行断言”。\\U\\1 表示将该字符替换为大写版本。\\1 是模式中用()括起来的第一组的反向引用。有关更多详细信息,请参见?regex

如果您只想大写第一个单词的第一个字母,请改用模式"^([a-z])


2
这是实际答案。我敦促提问者重新考虑他们的检查。 - Brash Equilibrium
1
反向引用是否必要?这样不会得到相同的结果吗?gsub("(\\b[a-z])", "\\U\\1", tolower(xx), perl=TRUE) - Stan
这种方法并不适用于所有语言,因为它也会将特殊字符(如变音符号)后面的字母大写。 - lillemets

13

这个问题涉及到Excel中的PROPER等价函数,(之前)被接受的回答基于:

proper=function(x) paste0(toupper(substr(x, 1, 1)), tolower(substring(x, 2)))

也许值得注意的是:

proper("hello world")
## [1] "Hello world"

使用Excel的 PROPER 函数将会返回 "Hello World"。如需进行与Excel的1:1映射,请参考@Matthew Plourde。

如果您实际上只需要将字符串的第一个字符设置为大写,您还可以考虑更短且稍微更快的版本:

proper=function(s) sub("(.)", ("\\U\\1"), tolower(s), pe=TRUE)

11

另一种方法使用stringi包。 stri_trans_general函数似乎将除初始字母外的所有字母转换为小写。

require(stringi)
x <- c('woRd Word', 'Word', 'word words')
stri_trans_general(x, id = "Title")
[1] "Word Word"  "Word"       "Word Words"

3
针对未来的访客:stringi包含一个名为stri_trans_totitle的函数,与本回答中提到的功能相同。不确定是否在该回答发布时已存在该函数。 - IceCreamToucan

5
我认为没有现成的,但你可以很容易地自己编写。
(dat <- data.frame(x = c('hello', 'frIENds'),
                   y = c('rawr','rulZ'),
                   z = c(16, 18)))
#         x    y  z
# 1   hello rawr 16
# 2 frIENds rulZ 18

proper <- function(x)
  paste0(toupper(substr(x, 1, 1)), tolower(substring(x, 2)))


(dat <- data.frame(lapply(dat, function(x)
  if (is.numeric(x)) x else proper(x)),
  stringsAsFactors = FALSE))

#         x    y  z
# 1   Hello Rawr 16
# 2 Friends Rulz 18

str(dat)
# 'data.frame':  2 obs. of  3 variables:
#   $ x: chr  "Hello" "Friends"
#   $ y: chr  "Rawr" "Rulz"
#   $ z: num  16 18

谢谢,这正是我在寻找的。这是一个很好的东西,应该成为基础的一部分 :) - Konrad
只是提醒一下,应用此函数后,函数中可用的数字列被更改为因子,这会稍微破坏图表,所以我不得不再将其更改为数字。 - Konrad
@Konrad 那么我会使用 data.frame(lapply(dat, function(x) if(is.numeric(x)) x else proper(x))) 或类似的东西。 - rawr
非常感谢,这是非常有用的解决方案。我在想是否将 if(is.numeric 部分移动到函数本身会更合理。 - Konrad
你也可以这样做。你还可以扩展该函数以处理不同类别的不同方式。 - rawr

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接