如何添加前导零?

Posted

技术标签:

【中文标题】如何添加前导零?【英文标题】:How to add leading zeros? 【发布时间】:2022-01-14 10:58:32 【问题描述】:

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

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

【问题讨论】:

假设你想在动物 id 之前添加 n 个零,你只需要这样做 data$anim = paste(rep(0, n), data$anim, sep = "") 当您说要“添加零”时,您可能不想将整数列转换为字符串/分类,以便在数据本身中添加零填充,您想要保持整数,在渲染输出时只打印前导零 【参考方案1】:

短版:使用formatCsprintf


更长的版本:

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

问题中的示例非常简单,因为所有值的开头位数都相同,所以让我们尝试一个更难的示例,将 10 的幂也设为 8。

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

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

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

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


str_pad 来自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"

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

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

stri_padstringi 中的工作方式与stringr 中的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's answer。


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

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

prettyNum 是另一个格式化函数,主要用于创建手动轴刻度标签。它特别适用于大范围的数字。

scales 包具有多个函数,例如 percentdate_formatdollar 用于专业格式类型。

【讨论】:

非常感谢您的大力帮助。我使用 formatC 为我的动画添加前导零,效果很好。 formatC(number or vector, width = 6, format = "d", flag = "0") 运行良好(R 版本 3.0.2 (2013-09-25))。谢谢。 以上述方式使用 formatC() 对我不起作用。它添加了空格而不是零。我做错什么了吗?我正在使用 R 版本 3.1.1。 @user1816679 听起来你忘记了flag = "0" ?sprintf 帮助页面的详细信息部分对此进行了描述。 “m.n:两个数字,用句点隔开,分别表示字段宽度(m)和精度(n)。”【参考方案2】:

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

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

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

【讨论】:

请注意sprintf 将数字转换为字符串(字符)。 感谢您的回答。我想将 13 位数字变为 14 位数字(添加前导零)。此功能似乎不适用于这种情况。它给了我一个错误: sprintf("%020d", 4000100000104) 中的错误:格式无效 '%020d';对数字对象使用格式 %f、%e、%g 或 %a。有什么建议吗? 尝试:sprintf("%014.0f", 4000100000104) sprintf 不适用于 R 3.4.1 是的。自 1.5.0 版以来没有变化。【参考方案3】:

扩展@goodside 的回复:

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

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

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

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

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

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

【讨论】:

无论出于何种原因,这个解决方案在 Linux 上不再适用于我。 @kdauria 的 str_pad 现在是我的首选。【参考方案4】:

stringr 包中的str_pad 是另一种选择。

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

【讨论】:

使用str_pad 时要非常小心,因为它可能会导致意外结果。 i.num = 600000; str_pad(i.num, width = 7, pad = "0") 会给你“006e+05”而不是“0600000”【参考方案5】:

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

【讨论】:

【参考方案6】:

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

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

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

使用magrittr 包中的%&gt;% 管道函数,它可能看起来像这样:

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

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

【讨论】:

【参考方案7】:
data$anim <- sapply(0, paste0,data$anim)

【讨论】:

【参考方案8】:

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

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

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)

对格式问题感到抱歉。

【讨论】:

以上是关于如何添加前导零?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 C sprintf 中添加用户定义的变量前导零?

如何在 Pandas 中为字符串添加前导零格式?

如何在shell中为for循环添加前导零? [复制]

如何将前导零添加到国家号码?

如何在Java(Android)中使用getMonth添加前导零[重复]

如何将前导数字标识符(不一定为零)添加到 r 中的字符串