生成随机字符串

43
我希望以以下方式生成随机字符串:ABCDE1234E,即每个字符串包含5个字符,4个数字,然后1个字符。

我用以下代码找到了一种创建此字符串的方法。

library(random)
string_5 <- as.vector(randomStrings(n=5000, len=5, digits=FALSE, upperalpha=TRUE,
                        loweralpha=FALSE, unique=TRUE, check=TRUE))
number_4 <- as.vector(randomNumbers(n=5000, min=1111, max=9999, col=5, base=10, check=TRUE))
string_1 <- as.vector(randomStrings(n=5000, len=1, digits=FALSE, upperalpha=TRUE,
                         loweralpha=FALSE, unique=FALSE, check=TRUE))
PAN.Number <- paste(string_5,number_4,string_1,sep = "")

但是这些函数执行起来需要很长时间,random 库需要网络连接。

> system.time(string_5 <- as.vector(randomStrings(n=5000, len=5, digits=FALSE, upperalpha=TRUE,
+                                                 loweralpha=FALSE, unique=TRUE, check=TRUE)))
   user  system elapsed 
   0.07    0.00    3.18 

有没有什么方法可以尝试减少执行时间?我也试过使用sample(),但我无法弄清楚。

7个回答

51

使用 @akrun 建议的 "stringi" 会更快,但以下方法也非常快速,而且不需要额外安装任何包:

myFun <- function(n = 5000) {
  a <- do.call(paste0, replicate(5, sample(LETTERS, n, TRUE), FALSE))
  paste0(a, sprintf("%04d", sample(9999, n, TRUE)), sample(LETTERS, n, TRUE))
}

示例输出:

myFun(10)
##  [1] "BZHOF3737P" "EPOWI0674X" "YYWEB2825M" "HQIXJ5187K" "IYIMB2578R"
##  [6] "YSGBG6609I" "OBLBL6409Q" "PUMAL5632D" "ABRAT4481L" "FNVEN7870Q"

33
我们可以使用stringi中的stri_rand_strings
library(stringi)
sprintf("%s%s%s", stri_rand_strings(5, 5, '[A-Z]'),
      stri_rand_strings(5, 4, '[0-9]'), stri_rand_strings(5, 1, '[A-Z]'))

或者更紧凑

do.call(paste0, Map(stri_rand_strings, n=5, length=c(5, 4, 1),
            pattern = c('[A-Z]', '[0-9]', '[A-Z]')))

基准测试

system.time({
    do.call(paste0, Map(stri_rand_strings, n=5000, length=c(5, 4, 1),
            pattern = c('[A-Z]', '[0-9]', '[A-Z]')))
    })
#  user  system elapsed 
#   0      0      0

使用OP的方法,我能够重现甚至针对预期输出其中一部分的计时。

system.time(string_5 <- as.vector(randomStrings(n=5000, len=5, digits=FALSE, upperalpha=TRUE,
                                              loweralpha=FALSE, unique=TRUE, check=TRUE)))
#  user  system elapsed 
#   0.86    0.24    5.52 

12
你可以直接执行以下操作: 随机抽取5个大写字母 随机抽取4个数字 随机抽取1个大写字母
digits = 0:9
createRandString<- function() {
  v = c(sample(LETTERS, 5, replace = TRUE),
        sample(digits, 4, replace = TRUE),
        sample(LETTERS, 1, replace = TRUE))
  return(paste0(v,collapse = ""))
}

这样可以更容易地进行控制,而且不需要花费太长时间。

3
你的性能问题来自于一开始使用了random包:可以理解你在互联网搜索中找到random::randomStrings()函数并认为它是生成随机字符串用于程序的好方法,但是random不适用于通用编程。它通过查询RANDOM.ORG服务器工作,这本质上比R内置的伪随机数生成器慢。
random包的文档中可以看到:

有许多情况下需要使用非确定性随机数。例如:
- 使用真正独立的种子在不同节点上启动分布式计算;
- 获取不依赖于特定操作系统或硬件功能的RNG的可移植初始化;
- 使用非确定性随机数验证模拟结果;
- 提供用于彩票抽奖或游戏的不确定性种子...

请注意,大多数示例都涉及到对R内置的伪随机数生成器进行种子化初始化(这些是同义词),而不是替换它们...

2
我们现在可以使用dplyr中的"rowwise"和"mutate",并使用library(stringi)中的stri_rand_strings函数来实现此操作:
df %>% 
rowwise() %>% 
mutate(unique_id = paste0(stri_rand_strings(1, 5, "[A-Z]"), stri_rand_strings(1, 4, "[0-9]"), stri_rand_strings(1, 1, "[A-Z]")))

这样可以避免创建函数的必要性。

1

如果有人在这里寻找生成随机文件名的方法,这是我使用的方法。我喜欢它的优雅。

library(dplyr)
runif(1, 1000000000000, 9999999999999) %>% round %>% as.character %>% paste0("/tmp/", ., ".png") 

注意:您可以通过将runif()中的1更改为所需的数字来轻松更改生成的随机字符串数量。

1
你可以使用ASCII表来精细控制最终字符串。
randString <- function(characters=0, numbers=0, symbols=0, lowerCase=0, upperCase=0) {
  ASCII <- NULL
  if(symbols>0)    ASCII <- c(ASCII, sample(c(33:47, 58:34, 91:96, 123:126), symbols))
  if(numbers>0)    ASCII <- c(ASCII, sample(48:57, numbers))
  if(upperCase>0)  ASCII <- c(ASCII, sample(65:90, upperCase))
  if(lowerCase>0)  ASCII <- c(ASCII, sample(97:122, lowerCase))
  if(characters>0) ASCII <- c(ASCII, sample(c(65:90, 97:122), characters))
  
  return( rawToChar(as.raw(sample(ASCII, length(ASCII)))) )
}

例子:

randString(characters=5, numbers=4)
# [1] "9fKW75o1N"

非常有用,谢谢!只有一个注意事项,在这一行中:if(symbols>0) ASCII <- c(ASCII, sample(c(33:47, 58:34, 91:96, 123:126), symbols)),应该是58:64 - GNicoletti

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接