如何生成随机数?


23

我想生成一个或几个用新行分隔的随机数。

如何做到这一点?


1
纯Vim吗?或者说,使用:python
muru

纯vim是首选,但如果不是内置的,则任何易于记忆的方法都可以。
kenorb

Answers:


20

没有内置的功能,因此您需要使用外部的东西。

UNIX Shell(/bin/sh

致电:

strings -n 1 < /dev/urandom | tr -d '[:space:]' | head -c15

system()是一个好方法。替换为tr,您只能获得数字grep

strings -n 1 < /dev/urandom | grep -o '[[:digit:]]' | head -c15

您可以像这样在Vim中使用它:

:echo system("strings -n 1 < /dev/urandom | grep -o '[[:digit:]]'  | head -c15")

数字15是您想要的数字数量(相应调整)。这应该在Linux,BSD,OSX和其他UNIX系统上起作用。在MS Windows上将无法使用。

另请参阅我的网络日志文章“ 从命令行生成密码 ”(那里有很多错误的解决方案)。

红宝石

Ruby可能是下一个最佳选择,因为Ruby脚本似乎比Python脚本更常见。获取随机数很容易:

:ruby puts Random.rand(10)

或获得15个号码:

:ruby 15.times { puts Random.rand(10) }

蟒蛇

您可以使用随机模块;得到一个数字:

:py import random; print(random.randint(0, 9))

或15个数字:

:py import random
:py for i in range(0, 15): print(random.randint(0, 9))

这对Python 2和3均适用。

Windows PowerShell

您可以Get-Random 用来获取随机数:

:echo system('Get-Random')

视窗 cmd.exe

Windows 7和更高版本应随PowerShell一起提供,但如果要获得最大的兼容性,可以使用cmd.exe。它具有一个特殊变量%RANDOM%

:echo system('@echo %RANDOM%')

注意:这不是很随机! ,它使用时间(!)


请注意,您无需使用Ruby或Python绑定即可使用Ruby或Python解决方案。您还可以创建一个单独的脚本,然后使用进行调用 system("python -c '...'")(显然,这确实需要安装ruby / python。


代替tr -d '[:space:]',也许tr -cd '[:digit:]'是grep过滤器?
muru 2015年

@muru我不知道,这将在OSX上,这就是为什么我没有使用它...您还可以得到一个换行分隔这样的数字,如OP问....工作
马丁Tournoij

如果真是这样... GNU击败了BSD。:P
muru 2015年

也可以使用外壳程序(系统)输入随机数,即:r! hexdump -n $((3*4)) -e '"%d"' /dev/urandom,将生成3个随机有符号整数。
HAL 9001

1
@kenorb这将正确使用外壳程序输入3个带符号的随机整数::r! hexdump -n $((3*4)) -e '"\%d\n"' /dev/urandom
HAL 9001

12

这是一个纯Vimscript解决方案。我没有创建它,它是由Charles E. Campbell开发的。您可以在此处找到带有他的代码的Github存储库。


该算法使用在Vim启动时生成的3个种子,并根据应用于种子的计算和排列生成一个伪随机数:

" Randomization Variables
" with a little extra randomized start from localtime()
let g:rndm_m1 = 32007779 + (localtime()%100 - 50)
let g:rndm_m2 = 23717810 + (localtime()/86400)%100
let g:rndm_m3 = 52636370 + (localtime()/3600)%100

变量范围被声明为全局变量,因为它们由生成器函数使用,但是可以限制为脚本(s:

这是生成器函数:

function! Rndm()
    let m4= g:rndm_m1 + g:rndm_m2 + g:rndm_m3
    if( g:rndm_m2 < 50000000 )
        let m4= m4 + 1357
    endif
    if( m4 >= 100000000 )
        let m4= m4 - 100000000
        if( m4 >= 100000000 )
            let m4= m4 - 100000000
        endif
    endif
    let g:rndm_m1 = g:rndm_m2
    let g:rndm_m2 = g:rndm_m3
    let g:rndm_m3 = m4
    return g:rndm_m3
endfun

回购包含以下功能:

  • 种子的“随机”初始化;
  • 从文本文件中读取一些用户定义的种子的方法;
  • 伪随机发生器
  • 几个随机函数:
    • 产生一定范围内随机数的函数
    • 骰子滚动功能
    • 随机交换序列整数列表的函数

这是我编写的用于测试生成器的快速测试:我生成了1000000个介于0和9之间的数字,并计算了每个数字的出现次数,这是结果:

0 : 100409
1 : 99435
2 : 100433
3 : 99578
4 : 100484
5 : 99948
6 : 100394
7 : 99649
8 : 99803
9 : 99867

如您所见,这一代似乎分布良好。我知道这在很大程度上不足以测试随机生成器,因此如果有空闲时间,我将尝试进行一些额外的分析。


7

这是一种在vim-randomtag插件中找到的方法,该方法基于以下信息:...当前时间微秒,仅在需要一些数字,对随机性质量不太关心或有安全方面的关注时可用:

function! s:randnum(max) abort
  return str2nr(matchstr(reltimestr(reltime()), '\v\.@<=\d+')[1:]) % a:max
endfunction

4

Vim不提供本机随机生成器,但是,如果您使用Python编译了vim,则以下方法将在行尾添加一个随机数字:

:py import vim, random; vim.current.line += str(random.randint(0, 9))

注意:要检查您的vim是否支持Python,请尝试::echo has('python')(1是)。

您还可以使用提供$RANDOM变量(使用bash / ksh / zsh的变量)的shell,该变量返回伪随机数(0-32767),例如:

:r! echo $RANDOM

要么:

:put =system('echo $RANDOM')

要么:

:r! od -An -td -N1 /dev/urandom

在Windows上,您必须安装Cygwin / MSYS / SUA,或%RANDOM%按照Carpetsmoker的建议使用变量。

如果您无权使用Shell和Python(作为解决方法),请使用当前时间戳记的最后几位数字,例如:

:put =reltimestr(reltime())[-2:]

注意:如果您经常使用它,请编写一个简单的函数,该函数将为return reltimestr(reltime())[-4:]

注意:以上方法仅返回伪随机整数,不应将其用于生成加密密钥。


要添加更多随机数,请按@:再次重复该命令。或以数字作为前缀(例如10@:),以添加更多由新行分隔的随机数。


有关:


它还可以与zsh,但不与shdashfishcsh,或tcsh...您可以使用:r! bash -c 'echo $RANDOM'...
马丁Tournoij

“从当前时间戳返回最后几位数字” ->这不是随机的。即使是出于非加密目的,花费时间来获取伪随机数几乎总是一个坏主意。如果时间戳的分辨率以秒为单位,并且每秒创建两次“ file。$ random”怎么办?糟糕!......此外,你永远不知道什么时候有人的要使用你的GetRandom()函数,其中良好的PRNG 的事情,所以最好只得到它从一开始就可能的话(这几乎总是能够在这里!)
马丁Tournoij

我不知道它的质量$RANDOM是什么,但是如果这不是一个较差的PRNG,那么这不是使用更差的PRNG的理由:-)相反,请升级到更好的PRNG!据我所知,/dev/urandom在所有bash通常可用的平台上都可用,因此我看不出使用它的原因。
马丁·图尔诺伊

1
我不知道$RANDOM。似乎是一个非常不错的小工具,即使它可能是“穷人RNG”(如@Carpetsmoker指出的那样),也绝对符合@kenorb(提出问题的人)“容易记忆”的要求。
Dalker

4

您可以使用rand()srand()函数,前提是您的Vim二进制文件包括补丁8.1.2342


例如,要生成由换行符分隔的10个随机数:

let seed = srand()
echo range(10)->map({-> rand(g:seed)})->join("\n")

要生成小于100的10个随机数:

let seed = srand()
echo range(10)->map({-> rand(g:seed) % 100})->join("\n")

要生成5个字符的10个随机字母字符串:

let seed = srand()
echo range(10)
   \ ->map({-> range(5)
   \           ->map({-> (97+rand(g:seed) % 26)->nr2char()})->join('')})
   \ ->join("\n")

要生成10个随机词(取自词典文件/usr/share/dict/words):

let seed = srand()
let words = readfile('/usr/share/dict/words')
let len = len(words)
echo range(10)->map({-> g:words[rand(g:seed) % g:len]})->join("\n")

要生成5个随机词的10个序列:

let seed = srand()
let words = readfile('/usr/share/dict/words')
let len = len(words)
echo range(10)
   \ ->map({-> range(5)
   \           ->map({-> g:words[rand(g:seed) % g:len]})->join()})
   \ ->join("\n")

生成随机UUID版本4:

" Based on this answer: /programming//a/38191078/9780968
let seed = srand()
let random_numbers = range(30)->map({-> rand(g:seed) % 16})
echo call('printf', ['%x%x%x%x%x%x%x%x-%x%x%x%x-4%x%x%x'] + random_numbers[:14])
 \ ..call('printf', ['-X%x%x%x-%x%x%x%x%x%x%x%x%x%x%x%x'] + random_numbers[15:])
 \   ->substitute('X', '89ab'[rand(seed) % 4], '')

要应用随机配色方案:

let seed = srand()
let colorschemes = getcompletion('', 'color')
let len = colorschemes->len()
exe 'colo '..colorschemes[rand(seed) % len]

3

我认为Vimscript中没有随机数的本机功能。

一种使用方式:python(在函数中使用,也许用10000和60替换为参数):

:python <<EOF
import vim
import random

line = vim.current.window.cursor[0]
r = getattr(__builtins__, 'xrange', range) # To make it work for both Python 2 & 3
vim.current.buffer[line:line] = list(map(str, random.sample(r(10000), 60)))
EOF

有关在Vim中使用Python脚本的快速介绍,请参见我对通过python在vim中创建框的回答。

由于vim.current.buffer是字符串列表,因此我们可以像在Python中那样为它分配字符串列表。random.sample这是我想到的在Python中获取随机整数列表的最简单方法。


@Carpetsmoker random.sample在Python 2上仅提供两个参数,它str是将事物转换为字符串的内置函数。让我查找等效的Py3(str将是相同的,必须检查xrangerandom.sample)。
muru

@Carpetsmoker aargh,错字。60后面的括号应该在10000之后。并且xrange在Python3中不是,因为它range是等效的(两者都不像rangePy2 那样实际构造列表)。
muru 2015年

@Carpetsmoker最终的区别是map在Py3中返回的是可迭代的列表,而不是列表,因此最后一行将使用list(map(str, random.sample(range(10000), 60)))
muru 2015年

好的,我可以自由地通过一些(较小的)更改来编辑您的帖子,以使其与Python 2和3兼容...
Martin Tournoij 2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.