如何添加前导零?


351

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

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之前添加两个或三个零该怎么办?


6
假设您想在动物ID之前添加n个零data$anim = paste(rep(0, n), data$anim, sep = "")
-Ramnath

2
当您说要“添加零”时,您可能不想将整数列转换为字符串/分类,以便在数据本身内部添加零填充,您希望将其保留为整数,仅打印前导零渲染输出时
smci 2015年

Answers:


552

简短版本:使用formatCsprintf


较长的版本:

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

该问题的示例非常容易,因为所有值的开头都具有相同的数字位数,因此让我们尝试一个更难的示例,使10的幂乘以8。

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

paste(以及它的变体paste0)通常是您遇到的第一个字符串操作函数。它们并不是真正为处理数字而设计的,但是它们可以用于处理数字。在最简单的情况下,我们总是必须在前面加上一个零,这paste0是最好的解决方案。

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

对于数字中数字位数可变的情况,您必须手动计算要添加多少个零,这太可怕了,您只能出于病态的好奇心而这样做。


str_padfrom的stringr工作方式与相似paste,因此可以更明确地表明您想填充内容。

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"

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

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

stri_padstringi作品完全像str_pad来自stringr


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_format以及dollar用于特殊格式的类型。


3
非常感谢您的大力帮助。我使用formatC在动画中添加了前导零,并且效果很好。
baz

2
formatC(数字或矢量,宽度= 6,格式=“ d”,标志=“ 0”)效果很好(R版本3.0.2(2013-09-25))。谢谢。
Mohamad Fakih 2013年

1
以上述方式使用formatC()对我不起作用。它添加了空格而不是零。我做错什么了吗?我正在使用R版本3.1.1。
user1816679

2
@ user1816679听起来就像您忘记了flag = "0"
Richie Cotton

1
?sprintf帮助页面的“详细信息”部分对此进行了说明。“ mn:两个数字,中间用句点分隔,表示字段宽度(m)和精度(n)。”
Richie Cotton

215

对于不管输入多少位都有效的通用解决方案data$anim,请使用sprintf函数。它是这样的:

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

就您而言,您可能想要: data$anim <- sprintf("%06d", data$anim)


14
请注意,sprintf将数字转换为字符串(字符)。
aL3xa

感谢您的回答。我想将13位数字设为14位(加上前导零)。在这种情况下,此功能似乎不起作用。它给了我一个错误:sprintf(“%020d”,4000100000104)错误:格式'%020d'无效;对数字对象使用格式%f,%e,%g或%a。有什么建议吗?
Rotail

试试:sprintf(“%014.0f”,4000100000104)
斯图尔特·麦克唐纳

sprintf不适用于R 3.4.1
Frank FYC

是的。自1.5.0版以来,它没有更改。
dash2

32

扩展@goodside的响应:

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

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

但是由于在Windows 7中sprintf()调用了OS的C sprintf()命令(在此进行了讨论),您将得到不同的结果:

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

因此,在Windows计算机上,解决方法是:

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

1
无论出于何种原因,该解决方案在Linux上都不再适用。str_pad现在是@kdauria的了。
水杉2016年

25

str_padstringr包装中选择。

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

4
请非常小心,str_pad因为它可能导致意外的结果。 i.num = 600000; str_pad(i.num, width = 7, pad = "0") 会给您“ 006e + 05”而不是“ 0600000”
Pankil Shah

2

这是一个通用的基本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标准,并且详细信息(尤其是用户错误下的行为)可能取决于平台


1

这是在字符串(例如CUSIP)中添加前导0的另一种选择,有时看起来像数字,并且许多应用程序(例如Excel)会破坏并删除前导0或将其转换为科学计数法。

当我尝试@metasequoia提供的答案时,返回的向量有前导空格而不是0s。这是由@ user1816679提到了同样的问题-和周围的去除引号0或更改%d%s不有所作为无论是。仅供参考,我正在使用在Ubuntu服务器上运行的RStudio服务器。这个小小的两步解决方案为我工作:

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

使用包中的%>%pipe函数,magrittr它看起来可能像这样:

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

我更喜欢一种功能的解决方案,但是它可以工作。


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

只是paste0(0, data$anim)会工作正常。
dash2

0

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

有人可能会发现这很有用:

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)

抱歉,格式化。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.