给定英国邮政编码的“模板”,例如“A9 9AA”,其中“A”是字母占位符,“9”是数字占位符,我想生成随机邮政编码字符串,如“H8 4GB” 。字母可以是任何大写字母,编号从0到9。
因此,如果模板是“AA9A 9AA”,那么我想要像“WC1A 9LK”这样的字符串。我现在忽略了生成“真正的”邮政编码,所以如果“WC1A”是一个有效的外向代码,我不会感到困扰。
我试图让stringi
包中的函数起作用,但问题似乎是替换或匹配模板中的“A”只会替换第一个替换,例如:
stri_replace_all_fixed("A9 9AA",c("A","A","A"), c("X","Y","Z"), vectorize_all=FALSE)
[1] "X9 9XX"
所以它不会用替换向量中的每个元素替换每个“A”(但这是设计)。
也许stringi
或者基础R中有一些我错过的东西 - 我想把它放在那些包中,所以我不会臃肿我正在做的事情。
蛮力方法是分割模板,进行替换,将结果粘贴在一起,但我想看看是否有更快,自然的矢量化解决方案。
总结一下:
foo("A9 9AA") # return like "B6 5DE"
foo(c("A9 9AA","A9 9AA","A9A 9AA")) # returns c("Y6 5TH","D4 8JH","W0Z 3KQ")
这是一个非矢量化版本,它依赖于构建表达式并对其进行评估......
random_pc <- function(fmt){
cc = gsub(" ",'c(" ")',gsub("9","sample(0:9,1)",gsub("A","sample(LETTERS,1)",strsplit(fmt,"")[[1]])))
paste(eval(parse(text=paste0("c(",paste(cc,collapse=","),")"))),collapse="")
}
> random_pc("AA9 9AA")
[1] "KO6 1AY"
答案 0 :(得分:4)
据我了解,OP希望以指定的格式随机创建UK POST CODE
。我认为sprintf
可以提供帮助:
sprintf("%s%s %d%d%s", sample(LETTERS,1),sample(LETTERS,1), sample(0:9,1),
sample(0:9,1), sample(LETTERS,1) )
#1] "BC 59D"
现在,如果目的是使用9
和A
提供格式,那么步骤将首先用9
和%d
替换A
{ {1}}。
选项#2 强>
使用%s
和paste0
使用自定义函数可以实现另一个选项:
sapply
答案 1 :(得分:1)
这是一个解决方案(矢量化懒惰的方式),它分割格式然后根据字符或数字替换:
randpc <- Vectorize(function(s){
s = strsplit(s,"")[[1]]
NUMS = as.character(0:9)
nLet = sum(s %in% LETTERS)
nDig = sum(s %in% NUMS)
s[s %in% LETTERS] = sample(LETTERS, nLet, replace=TRUE)
s[s %in% NUMS] = sample(NUMS, nDig, replace=TRUE)
paste0(s, collapse="")
})
返回显示格式字符串的命名向量具有有用的副作用:
> randpc(c("AA9 9AA","A9 9AA"))
AA9 9AA A9 9AA
"QS4 4LW" "S9 7EU"
它的灵活性在于它可以根据另一个邮政编码创建邮政编码,因为它接受格式字符串中的任何字母或数字:
> randpc(rep("LA1 4YF",3))
LA1 4YF LA1 4YF LA1 4YF
"OL2 5OJ" "YK3 3YB" "FV0 1LW"
答案 2 :(得分:0)
我不确定什么算是蛮力,因为字符串上的拆分替换组合工作流对我来说似乎最直观。但是,我的第一次尝试非常慢,有很多模板。我也曾希望stri_replace_all(replacement = sample(LETTERS, 1))
这样的东西能起作用,但它也只能用同一个字母代替。
这是使用stri_replace_first
稍微不同的方法,替换模板字符的第一个实例,直到没有模板字符为止。这意味着我将模板切换为字母小写l
和数字n
,因为邮政编码只有大写字母和数字(据我所知)。我认为100k模板的运行时间更合理(~10秒),这也仅使用stringi
。
library(stringi)
make_postcodes <- function(templates){
postcodes <- templates
while (any(stri_detect_regex(postcodes, "l|n"))){
for (i in 1:length(templates)){
postcodes[i] <- stri_replace_first_fixed(
str = postcodes[i],
pattern = "l",
replacement = sample(LETTERS, 1)
)
postcodes[i] <- stri_replace_first_fixed(
str = postcodes[i],
pattern = "n",
replacement = sample(0:9, 1)
)
}
}
postcodes
}
make_postcodes("ln nll")
#> [1] "W8 3MX"
make_postcodes(c("ln nll", "ln nll", "lnl nll"))
#> [1] "H1 6TN" "C5 6YI" "A3I 2DB"
test = stri_trim_both(stri_rand_strings(100000, sample(5:9, 1), pattern = "[nl\\ ]"))
tictoc::tic("Time to convert 100,000 templates")
x <- make_postcodes(test)
tictoc::toc()
#> Time to convert 100,000 templates: 12.03 sec elapsed
head(test)
#> [1] "lnnl" "ll l" "nl n" "ll l" "ll l" "ll n"
head(x)
#> [1] "G91U" "HU N" "2Q 7" "EU Z" "PD I" "SM 4"
由reprex package(v0.2.0)创建于2018-04-06。