如何加前导零?

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

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前加两个或三个0呢?

375768 次浏览

对于一个通用的解决方案,不管data$anim中有多少位数字,都可以使用sprintf函数。它是这样工作的:

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

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

简短的版本:使用formatCsprintf


更长的版本:

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

这个问题的例子很简单,因为所有的值一开始都有相同的位数,所以让我们尝试一个更难的例子,让10的幂的宽度也为8。

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

paste(和它的变体paste0)通常是你遇到的第一个字符串操作函数。它们实际上并不是为操纵数字而设计的,但它们可以用于此。在简单的情况下,我们总是必须前置一个0,paste0是最好的解决方案。

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

对于数字中有可变位数的情况,您必须手动计算要前置多少个零,这已经够可怕的了,您只应该出于病态的好奇心这样做。


来自stringrstr_padpaste的工作原理类似,这使得你想要填充的东西更加明确。

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

同样,它并不是为数字设计的,所以更困难的情况需要稍微考虑一下。我们应该只能说“pad with 0 to width 8”,但是看看这个输出:

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

你需要设置科学惩罚选项,以便数字总是使用固定符号(而不是科学符号)格式化。

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

stringi中的stri_padstringr中的str_pad完全相同。


formatC是C函数printf的接口。使用它需要对底层函数的奥秘有所了解(见链接)。在这种情况下,重要的点是width参数,format为“整数”的"d",以及"0" flag用于前置零。

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,但语法不同。

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,但有另一个接口。

prettyNum是另一个格式化函数,主要用于创建手动轴标记标签。它对大范围的数字尤其有效。

scales包有几个特殊格式类型的函数,如percentdate_formatdollar

扩展@goodside的回应:

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

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

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

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

所以在Windows机器上的工作是:

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

stringr包中的str_pad是一种替代方法。

anim = 25499:25504
str_pad(anim, width=6, pad="0")
data$anim <- sapply(0, paste0,data$anim)

下面是另一种将前导0添加到字符串(如CUSIPs)的替代方法,它有时看起来像一个数字,许多应用程序(如Excel)将破坏并删除前导0或将其转换为科学符号。

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

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

使用magrittr包中的%>%管道函数,它看起来像这样:

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

我更喜欢一个功能单一的解决方案,但它确实可行。

在其他情况下,你希望数字字符串是一致的,我做了一个函数。

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

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)

对不起,格式不对。

下面是一个可推广的基R函数:

pad_left <- function(x, len = 1 + max(nchar(x)), char = '0'){


unlist(lapply(x, function(x) {
paste0(
paste(rep(char, len - nchar(x)), collapse = ''),
x
)
}))
}


pad_left(1:100)

我喜欢sprintf,但它带有如下警告:

然而,实际的实现将遵循C99标准,细节(特别是用户错误下的行为)可能取决于平台