首页 文章

如何添加前导零?

提问于
浏览
277

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

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

8 回答

  • 1

    简短版本:使用formatCsprintf .


    版本较长:

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

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

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

    paste (它的变体 paste0 )通常是您遇到的第一个字符串操作函数 . 它们并非真正用于操纵数字,但它们可用于此 . 在我们总是必须预先设置一个零的简单情况下, 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"
    

    同样,它并不是真正设计用于数字,所以更难的情况需要一点思考 . 我们应该只能说“用零填充宽度为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"
    

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


    formatC 是C函数printf的接口 . 使用它需要一些基础功能的基础知识(参见链接) . 在这种情况下,重要的是 width 参数, format 为"integer" "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,用于专业格式类型 .

  • 26

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

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

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

  • 429

    扩展@ goodside的回复:

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

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

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

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

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

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

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

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

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

    当我尝试@metasequoia提供的答案时,返回的向量具有前导空格而不是 0 . 这与@ 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 = .)

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

  • 190

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

  • 2

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

    有人可能会发现这一点有用:

    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)
    

    抱歉格式化 .

相关问题