I would like to generate one or few random numbers separated by new line.
How this can be done?
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?
– muru
Feb 14 '15 at 23:33
:r! hexdump -n $((3*4)) -e '"%d"' /dev/urandom, would generate 3 random signed integers.
– jyalim
Feb 15 '15 at 07:13
444204315-1248057303-74280604.
– kenorb
Feb 16 '15 at 14:09
:echo system(... is just printing on the screen, can you modify the example to paste into the editor?
– kenorb
Feb 16 '15 at 14:12
:r! hexdump -n $((3*4)) -e '"\%d\n"' /dev/urandom
– jyalim
Feb 16 '15 at 17:49
%u as a format would be better, since that's unsigned? This should remove negative numbers & the associated - character ... Also, why not just type 12 insyead of $((3*4))? That way it will work in all shells...
– Martin Tournoij
Feb 16 '15 at 20:58
%u may be better suited.
– jyalim
Feb 17 '15 at 00:49
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' ...
– Martin Tournoij
Feb 15 '15 at 23:24
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!)
– Martin Tournoij
Feb 16 '15 at 10:06
$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.
– Martin Tournoij
Feb 16 '15 at 10:59
$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".
– Dalker
Oct 07 '16 at 14:46
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).
– muru
Feb 14 '15 at 23:47
xrange is not in Python3 because range is equivalent (neither actually constructs a list, unlike range in Py2).
– muru
Feb 14 '15 at 23:55
map in Py3 returns an iterable and not a list, so the last line would use list(map(str, random.sample(range(10000), 60)))
– muru
Feb 14 '15 at 23:58
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? – muru Feb 14 '15 at 22:28