I would like to generate one or few random numbers separated by new line.
How this can be done?
Starting with Vim 8.1.2342, you can make use of the rand() and srand() functions.
Here is an example:
let g:seed = srand() echo rand(g:seed) % 100 " to echo a random number between 0-99 For older Vims, you'll have to fall back to calling some external commands (or use the Python, Perl, Tcl, MzScheme, Ruby, Lua language interfaces, if your Vim comes with those enabled).
/bin/sh)Calling:
strings -n 1 < /dev/urandom | tr -d '[:space:]' | head -c15 with system() is a good way. You can get only numbers by replacing tr with grep:
strings -n 1 < /dev/urandom | grep -o '[[:digit:]]' | head -c15 You can use this in Vim like so:
:echo system("strings -n 1 < /dev/urandom | grep -o '[[:digit:]]' | head -c15") The number 15 is the amount of numbers you want (adjust accordingly). This should work on Linux, BSD, OSX, and other UNIX systems. It won't work on MS Windows.
Also see my weblog post "Generate passwords from the commandline" (there are a lot of bad solutions for this out there).
Ruby is probably the next best choice, since Ruby scripting seems to be a bit more common than Python scripting. Getting a random number is easy:
:ruby puts Random.rand(10) Or to get 15 numbers:
:ruby 15.times { puts Random.rand(10) } You can use the random module; to get a single number:
:py import random; print(random.randint(0, 9)) Or a 15 numbers:
:py import random :py for i in range(0, 15): print(random.randint(0, 9)) This should work for both Python 2 & 3.
You can use Get-Random to get a random number:
:echo system('Get-Random') cmd.exeWindows 7 and later should ship with PowerShell, but if you want maximum compatibility you can use cmd.exe. It has a special variable %RANDOM%:
:echo system('@echo %RANDOM%') Note: This is not very random! , it uses the time (!)
Note that you don't need to use the Ruby or Python bindings to use the Ruby or Python solutions; you could also create a separate script and call them with system("python -c '...'") (this does require that ruby/python is installed, obviously.
tr -d '[:space:]', perhaps tr -cd '[:digit:]' for the grep filter? :r! hexdump -n $((3*4)) -e '"%d"' /dev/urandom, would generate 3 random signed integers. :r! hexdump -n $((3*4)) -e '"\%d\n"' /dev/urandom Here is a pure vimscript solution. I did not create it, it was developed by Charles E. Campbell. You can find a Github repo with his code here.
The algorithm uses 3 seeds generated at Vim startup and generate a pseudo-random number based on calculations and permutations applied to the seeds:
" 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 The variables scope is declared as global because they are used by the generator function but it could be restricted to the script (s:)
And here is the generator function:
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 The repo includes the following functions:
Here is a quick test I wrote to test the generator: I generated 1000000 numbers between 0 and 9 and counted the number of occurrences of each number here are the results:
0 : 100409 1 : 99435 2 : 100433 3 : 99578 4 : 100484 5 : 99948 6 : 100394 7 : 99649 8 : 99803 9 : 99867 As you can see the generation seems to be well distributed. I'm aware that this is largely not enough to test a random generator so I'll try to make some extra analysis if I have some free time.
This is a method found in the vim-randomtag plugin, which is based on reading ... current time microseconds, usable when you just want some number, you don't care much about randomness quality, or have security concerns etc.:
function! s:randnum(max) abort return str2nr(matchstr(reltimestr(reltime()), '\v\.@<=\d+')[1:]) % a:max endfunction You can use the rand() and srand() functions, provided your Vim binary includes the patch 8.1.2342.
As an example, to generate 10 random numbers separated by newlines:
let seed = srand() echo range(10)->map({-> rand(g:seed)})->join("\n") To generate 10 random numbers all inferior to 100:
let seed = srand() echo range(10)->map({-> rand(g:seed) % 100})->join("\n") To generate 10 random alphabetical strings of 5 characters:
let seed = srand() echo range(10) \ ->map({-> range(5) \ ->map({-> (97+rand(g:seed) % 26)->nr2char()})->join('')}) \ ->join("\n") To generate 10 random words (taken from the dictionary file /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") To generate 10 sequences of 5 random words:
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") To generate a random UUID version 4:
" Based on this answer: https://stackoverflow.com/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], '') To apply a random color scheme:
let seed = srand() let colorschemes = getcompletion('', 'color') let len = colorschemes->len() exe 'colo '..colorschemes[rand(seed) % len] Vim doesn't offer native random generator, however if you have vim compiled with Python, the following method will append a random digit at the end of your line:
:py import vim, random; vim.current.line += str(random.randint(0, 9)) Note: To check if your vim supports Python, try: :echo has('python') (1 for yes).
You can also use shell which offers $RANDOM variable (works with bash/ksh/zsh) which returns a pseudorandom (0-32767), in example:
:r! echo $RANDOM or:
:put =system('echo $RANDOM') or:
:r! od -An -td -N1 /dev/urandom On Windows, you've to have Cygwin/MSYS/SUA installed, or use %RANDOM% variable as Carpetsmoker suggested.
If you don't have access to shell and Python, as for workaround, you use last few digits from the current timestamp, in example:
:put =reltimestr(reltime())[-2:] Note: If you're using it quite often, write a simple function which will return reltimestr(reltime())[-4:].
Note: Above methods returns only a pseudorandom integer which should not be used to generate an encryption key.
To add more random numbers please press @: to repeat the command again. Or prefix with number (like 10@:) to add much more of random numbers separated by new lines.
Related:
zsh, but not with sh, dash, fish, csh, or tcsh ... You could use :r! bash -c 'echo $RANDOM' ... GetRandom() function where good prng does matter, so it's better to just get it right from the start if possible (and it's almost always possible here!) $RANDOM is, but if this is a poor PRNG then that's not a reason to use an even poorer PRNG :-) Instead, upgrade to a better PRNG! As far as I know, /dev/urandom is available on all platforms where bash is commonly available, so I don't see a reason to not use it. $RANDOM. Seems like a very nice little tool, and even though it may be a "poor's man RNG" (as @Carpetsmoker points out), it definitely fits @kenorb's (who asked the question) requirement of "easily memorable". I don't think there's a native function for random numbers in Vimscript.
A way using :python (use it in a function, perhaps, with 10000 and 60 replaced by parameters):
: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 See my answer to Making a box in vim via python for a quick intro on Python scripting in Vim.
Since vim.current.buffer is a list of strings, we can assign a list of strings to it the way we would in Python. random.sample is just the simplest way I can think of to get a list of random integers in Python.
random.sample repuires only two arguments on Python 2, str is the builtin function to convert things to strings. Let me look up the Py3 equivalents (str would be the same, will have to check xrange and random.sample). xrange is not in Python3 because range is equivalent (neither actually constructs a list, unlike range in Py2). map in Py3 returns an iterable and not a list, so the last line would use list(map(str, random.sample(range(10000), 60))) Vim v8.1.2342 add rand and srand function.
I prefer this way to generate 20 random numbers in range 0-100 in current buffer:
:put =rand()%100 20@: If you'd like to use a source outside your computer, random dot org will do. The command line is a bit not-easily-remembered, so I'd put it in a shell script, but this will give you twenty four-digit decimal random numbers.
:r!curl -s "https://www.random.org/integers/?num=20&min=1000&max=9990&col=1&base=10&format=plain&rnd=new"
:python?