提问



我有一组看起来像这样的数据:


anim <- c(25499,25500,25501,25502,25503,25504)
sex  <- c(1,2,2,1,2,1)
wt   <- c(0.8,1.2,1.0,2.0,1.8,1.4)
data <- data.frame(anim,sex,wt)

data
   anim sex  wt anim2
1 25499   1 0.8     2
2 25500   2 1.2     2
3 25501   2 1.0     2
4 25502   1 2.0     2
5 25503   2 1.8     2
6 25504   1 1.4     2


我希望在每个动物id之前添加一个零:


data
   anim sex  wt anim2
1 025499   1 0.8     2
2 025500   2 1.2     2
3 025501   2 1.0     2
4 025502   1 2.0     2
5 025503   2 1.8     2
6 025504   1 1.4     2


为了感兴趣,如果我需要在动物id之前添加两个或三个零,该怎么办?

最佳参考


简短版本:使用formatCsprintf[62] [63]





版本较长:


有几种功能可用于格式化数字,包括添加前导零。哪一个最好取决于您想要做的其他格式。


问题的例子非常简单,因为所有的值都有相同的数字位数,所以让我们尝试一个更难的例子来制作10宽度8的幂。


anim <- 25499:25504
x <- 10 ^ (0:5)





paste (它的变体paste0)通常是你遇到的第一个字符串操作函数。它们并非真正用于操纵数字,但它们可以是用于此。在我们总是必须预先设置一个零的简单情况下,paste0是最好的解决方案。[64]


paste0("0", anim)
## [1] "025499" "025500" "025501" "025502" "025503" "025504"


对于数字中存在可变位数的情况,您必须手动计算要预先设置的零数,这非常可怕,您应该只是出于病态的好奇心。





来自stringr str_pad paste的工作方式类似,更明确地表示你想要填充内容。[65]


library(stringr)
str_pad(anim, 6, pad = "0")
## [1] "025499" "025500" "025501" "025502" "025503" "025504"


同样,它并不是真的设计用于数字,所以更难的情况需要一点思考。我们应该只能说用零填充宽度8,但看看这个输出:


str_pad(x, 8, pad = "0")
## [1] "00000001" "00000010" "00000100" "00001000" "00010000" "0001e+05"


您需要设置科学惩罚选项,以便始终使用固定符号(而不是科学符号)格式化数字。[66]


library(withr)
with_options(
  c(scipen = 999), 
  str_pad(x, 8, pad = "0")
)
## [1] "00000001" "00000010" "00000100" "00001000" "00010000" "00100000"





stringi中的 stri_pad stringrstr_pad完全相同。[67]





formatC 是C函数printf的接口。使用它需要一些基础功能的基础知识(参见链接)。在这种情况下,重要的点是width参数,format"d"为整数,"0" flag为前置零。[68] [69]


formatC(anim, width = 6, format = "d", flag = "0")
## [1] "025499" "025500" "025501" "025502" "025503" "025504"
formatC(x, width = 8, format = "d", flag = "0")
## [1] "00000001" "00000010" "00000100" "00001000" "00010000" "00100000"


这是我最喜欢的解决方案,因为它很容易修改宽度,并且功能足以进行其他格式更改。





sprintf 是同名C函数的接口;喜欢formatC,但语法不同。 [70]


sprintf("%06d", anim)
## [1] "025499" "025500" "025501" "025502" "025503" "025504"
sprintf("%08d", x)
## [1] "00000001" "00000010" "00000100" "00001000" "00010000" "00100000"


sprintf的主要优点是您可以在较长的文本位中嵌入格式化的数字。


sprintf(
  "Animal ID %06d was a %s.", 
  anim, 
  sample(c("lion", "tiger"), length(anim), replace = TRUE)
)
## [1] "Animal ID 025499 was a tiger." "Animal ID 025500 was a tiger."
## [3] "Animal ID 025501 was a lion."  "Animal ID 025502 was a tiger."
## [5] "Animal ID 025503 was a tiger." "Animal ID 025504 was a lion." 


另见goodside的回答。





为了完整性,值得一提的是偶尔有用的其他格式化函数,但没有预先添加零的方法。


format ,用于格式化任何类型对象的通用函数,带有数字方法。它有点像formatC,但还有另一个界面。[72]


prettyNum 是另一种格式化功能,主要用于创建手动轴刻度标签。它适用于广泛的数字。[73]


scales 包具有多种功能,如percentdate_formatdollar,适用于专业格式类型。[74] [75]]] [76]

其它参考1


对于无论data$anim中有多少位都有效的一般解决方案,请使用sprintf功能。它的工作原理如下:


sprintf("%04d", 1)
# [1] "0001"
sprintf("%04d", 104)
# [1] "0104"
sprintf("%010d", 104)
# [1] "0000000104"


在你的情况下,你可能想要:data$anim <- sprintf("%06d", data$anim)

其它参考2


扩展@goodside的回复:


在某些情况下,您可能希望用零填充字符串(例如fips代码或其他类似数字的因子)。在OSX/Linux中:


> sprintf("%05s", "104")
[1] "00104"


但是因为sprintf()调用操作系统的C sprintf()命令,在这里讨论,在Windows 7中你会得到不同的结果:[77]


> sprintf("%05s", "104")
[1] "  104"


所以在Windows机器上,解决方法是:


> sprintf("%05d", as.numeric("104"))
[1] "00104"

其它参考3


来自stringr包的str_pad是另一种选择。


anim = 25499:25504
str_pad(anim, width=6, pad="0")

其它参考4


data$anim <- sapply(0, paste0,data$anim)

其它参考5


这是另一种方法,可以将字符串添加到字符串,例如CUSIP,它有时看起来像一个数字,许多应用程序(如Excel)将损坏并删除前导0或将它们转换为科学记数法。 [78]


当我尝试@metasequoia提供的答案时,返回的向量具有前导空格而不是0 s。这与@ user1816679提到的问题相同 - 删除0周围的引号或从%d更改为%s也没有任何区别。仅供参考,我正在使用在Ubuntu服务器上运行的RStudio Server。这个小小的两步解决方案对我有用:


gsub(pattern = " ", replacement = "0", x = sprintf(fmt = "%09s", ids[,CUSIP]))


使用magrittr包中的%>%管道函数,它可能如下所示:


sprintf(fmt = "%09s", ids[,CUSIP]) %>% gsub(pattern = " ", replacement = "0", x = .)


我更喜欢单功能解决方案,但它有效。

其它参考6


对于您希望数字字符串保持一致的其他情况,我创建了一个函数。


有人可能会觉得这很有用:


idnamer<-function(x,y){#Alphabetical designation and number of integers required
    id<-c(1:y)
    for (i in 1:length(id)){
         if(nchar(id[i])<2){
            id[i]<-paste("0",id[i],sep="")
         }
    }
    id<-paste(x,id,sep="")
    return(id)
}
idnamer("EF",28)


抱歉格式化。