向R中的字母数字字符串添加数字的有效方法

时间:2018-12-06 21:13:57

标签: r string tidyr stringr

我有一个data.frame,其ID由字母数字字符序列(例如id = c(A001, A002, B013))组成。我在stringrstirngi下寻找一个简单的函数,该函数可以轻松地对此字符串进行数学运算(id + 1应该返回c(A002, A003, B014))。

我做了一个自定义函数来解决这个问题,但是我感觉必须有一种更好/更有效/在封装内的方法来实现这一目标。

str_add_n <- function(df, string, n, width=3){

  string <- enquo(string)

  ## split the string using pattern
df <-  df %>%
    separate(!!string,
             into = c("text", "num"), 
             sep = "(?<=[A-Za-z])(?=[0-9])",
             remove=FALSE
    ) %>%
    mutate(num = as.numeric(num),
           num = num + n,
           num = stringr::str_pad(as.character(num),
                                  width = width,
                                  side = "left",
                                  pad = 0 
                                  )
           ) %>%
    unite(next_string, text:num, sep = "")


return(df)  
}

让我们做个玩具df

df <- data.frame(id = c("A001", "A002", "B013"))
str_add_n(df, id, 1)
    id next_string
1 A001        A002
2 A002        A003
3 B013        B014

再次,这行得通,我想知道是否有更好的方法来做到这一点,欢迎所有调整!

更新

根据建议的答案,我进行了一些基准测试,看来两者都非常接近,我倾向于使用str_add_n_2(我改了名称,以便能够同时运行两者,并接受了{ {1}})

x<-as.character(x)

哪个产量

microbenchmark::microbenchmark(question = str_add_n(df, id, 1),
 answer = df %>% mutate_at(vars(id), funs(str_add_n_2(., 1))),
 string_add = df %>% mutate_at(vars(id), funs(string_add(as.character(.)))))

欢迎进行更多调整!

2 个答案:

答案 0 :(得分:4)

这里是gsubfn

的一种方式
id <- c("A001", "A002", "B013")

library(gsubfn)
gsubfn("([0-9]+)", function(x) sprintf("%03.0f", as.numeric(x) + 1), id)
#[1] "A002" "A003" "B014"

您可以使其功能

string_add <- function(string, add = 1, width = 3) {
  gsubfn::gsubfn("([0-9]+)", function(x) sprintf(paste0("%0", width, ".0f"), as.numeric(x) + add), string)
}

string_add(id, add = 10, width = 5)
#"A00011" "A00012" "B00023"

答案 1 :(得分:3)

我建议,基于字符串的 vector 定义函数要容易得多,而不是对其进行硬编码以查找框架中的列会更容易。对于后者,您始终可以使用类似mutate_at(vars(id,...), funs(str_add_n))之类的东西。

str_add_n <- function(x, n = 1L) {
  gr <- gregexpr("\\d+", x)
  reg <- regmatches(x, gr)
  widths <- nchar(reg)
  regmatches(x, gr) <- sprintf(paste0("%0", widths, "d"), as.integer(reg) + n)
  x
}

vec <- c("A001", "A002", "B013")
str_add_n(vec)
# [1] "A002" "A003" "B014"

如果在框架中:

df <- data.frame(id = c("A001", "A002", "B013"), x = 1:3,
                 stringsAsFactors = FALSE)
library(dplyr)
df %>%
  mutate_at(vars(id), funs(str_add_n(., 3)))
#     id x
# 1 A004 1
# 2 A005 2
# 3 B016 3

注意:这悄悄地需要真正的character,而不是factor ...一种可能的防御策略可能是在函数定义中添加x <- as.character(x)