使用 stringr 或 gsub 在字符数据的开头附加一个数字

Append a digit at the beginning of character data using stringr or gsub

我有一个名为DATA_TEST的数据集。这个数据框包含字符format.You中的6个观察值,可以在下面看到table。

dput(DATA_TEST)
structure(list(Ten_digits = c("NA", "207", "0101", "0208 90", 
"0206 90 99 00", "103")), .Names = "Ten_digits", row.names = c(NA, 
-6L), class = "data.frame")
# -------------------------------------------------------------------------
# > DATA_TEST
#       Ten_digits
# 1            NA
# 2           207
# 3          0101
# 4       0208 90
# 5 0206 90 99 00
# 6           103

所以我的目的是使用 stringr 或其他包转换此数据框,如下图所示。实际上代码需要做一件事或更精确 首先必须只找到像207103这样的三位变量,并将这些变量转换为02070103。 在下面的 table 中,您终于可以看到 table 应该是什么样子了。

# > Desired Output
#       Ten_digits
# 1            NA
# 2          0207
# 3          0101
# 4       0208 90
# 5 0206 90 99 00
# 6          0103

那么有人可以帮我处理这段代码吗?

您可以使用 stringr 中的 str_length:

library(tidyverse) # in order to load all required packages at once

DATA_TEST %>% 
  mutate(Ten_digits = case_when(
    str_length(Ten_digits) == 3 ~ paste0("0", Ten_digits),
    TRUE ~ Ten_digits
    ))

# Ten_digits
#1            NA
#2          0207
#3          0101
#4       0208 90
#5 0206 90 99 00
#6          0103

str_length 允许您向量化字符向量的长度:来自 function's documentation:

Technically this returns the number of "code points", in a string. One code point usually corresponds to one character(...).

case_when 允许向量化多个 if_else 语句。

如评论中所述,可以使用ifelseif_else,比case_when更直接。请参阅以下微基准测试中的示例:

microbenchmark::microbenchmark(
  DATA_TEST %>% 
    mutate(Ten_digits = case_when(
      str_length(Ten_digits) == 3 ~ paste0("0", Ten_digits),
      TRUE ~ Ten_digits
    )),
  DATA_TEST %>% 
    mutate(Ten_digits = ifelse(
      str_length(Ten_digits) == 3, paste0("0", Ten_digits),
      Ten_digits
    )),
  DATA_TEST %>% 
    mutate(Ten_digits = if_else(
      str_length(Ten_digits) == 3, paste0("0", Ten_digits),
      Ten_digits
    ))
)

#     min       lq      mean  median       uq      max neval
# 785.809 806.9130 1051.9314 858.217 1193.865 2445.434   100  # case_when
# 613.398 623.3985  862.6720 636.858  822.027 8610.763   100  # ifelse
# 625.485 641.1370  822.3502 664.135  894.812 1995.932   100  # if_else

我们可以简单地通过在 3 个字符的字符串前面粘贴一个 0 来做到这一点,即

DATA_TEST$Ten_digits[nchar(DATA_TEST$Ten_digits) == 3] <- paste0("0", DATA_TEST$Ten_digits[nchar(DATA_TEST$Ten_digits) == 3])
DATA_TEST

#     Ten_digits
#1            NA
#2          0207
#3          0101
#4       0208 90
#5 0206 90 99 00
#6          0103

您可以使用简单的正则表达式 sub:

DATA_TEST<-data.frame(Ten_digits=c("NA","207","0101","0208 90","0206 90 99 00","103"),stringsAsFactors = FALSE)
DATA_TEST$Ten_digits <- sub("^(\d{3})$", "0\1", DATA_TEST$Ten_digits)
DATA_TEST
## => Ten_digits
1            NA
2          0207
3          0101
4       0208 90
5 0206 90 99 00
6          0103

在这里,^(\d{3})$ 匹配一个三位数字符串并将数字捕获到第 1 组(因为模式在括号内)并且 0 替换模式插入一个 0 并添加返回第 1 组中的整个匹配值。

图案详情

  • ^ - 字符串开头
  • (\d{3}) - 第 1 组:三位数
  • $ - 字符串结尾。

您可以使用 stingr 中的 str_pad。请注意,它会填充长度小于 4 个字符的任何字符串,因此如果您特别想关注长度为 3 的字符串,则需要修改代码。此外,如果您有文字 [=,则不需要 ifelse 14=] 而不是 "NA"。 -

DATA_TEST %>% 
  mutate(
    Ten_digits = ifelse(Ten_digits == "NA", "NA", str_pad(Ten_digits, width = 4, pad = 0))
  )

     Ten_digits
1            NA
2          0207
3          0101
4       0208 90
5 0206 90 99 00
6          0103