Как генерировать случайные числа?

23

Я хотел бы создать одно или несколько случайных чисел, разделенных новой строкой.

Как это можно сделать?

kenorb
источник
1
Чистый Вим? Или, скажем, используя :python?
Муру
Чистый vim предпочтителен, но если он не встроенный, подойдет любой легкий запоминающийся метод.
Кенорб

Ответы:

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')

Windows 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 Я не уверен, что это будет работать на OSX, поэтому я не использовал его ... Вы также получаете номера, разделенные символом новой строки таким образом, как ОП спросил ...
Мартин Турной
Если это так .... GNU побеждает BSD. : P
Муру
Можно также использовать оболочку (систему) для ввода случайных чисел, то есть :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 . Я не создал его, он был разработан Чарльзом Э. Кэмпбеллом. Вы можете найти репозиторий Github с его кодом здесь .


Алгоритм использует 3 начальных числа, сгенерированных при запуске Vim, и генерирует псевдослучайное число на основе вычислений и перестановок, примененных к начальным значениям:

" 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

Как вы можете видеть, поколение, кажется, хорошо распределено. Я знаю, что этого недостаточно для тестирования генератора случайных чисел, поэтому я попытаюсь провести дополнительный анализ, если у меня будет немного свободного времени.

statox
источник
7

Этот метод найден в плагине vim-randomtag , который основан на чтении ... микросекунд текущего времени, который можно использовать, когда вам просто нужно какое-то число, вас не волнует качество случайности или проблемы с безопасностью и т. Д .:

function! s:randnum(max) abort
  return str2nr(matchstr(reltimestr(reltime()), '\v\.@<=\d+')[1:]) % a:max
endfunction
VanLaser
источник
4

Vim не предлагает собственный генератор случайных чисел, однако если у вас есть vim, скомпилированный с Python, следующий метод добавит случайную цифру в конце вашей строки:

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

Примечание: чтобы проверить, поддерживает ли ваш vim Python, попробуйте: :echo has('python')(1 для да).

Вы также можете использовать оболочку, которая предлагает $RANDOMпеременную (работает с bash / ksh / zsh), которая возвращает псевдослучайный (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@:), чтобы добавить гораздо больше случайных чисел, разделенных новыми строками.


Связанный:

kenorb
источник
Она также работает с zsh, но не с sh, dash, fish, csh, или tcsh... Вы можете использовать :r! bash -c 'echo $RANDOM'...
Martin Tournoij
msgstr "вернуть последние несколько цифр из текущей метки времени" -> Это не случайно. Использование времени для получения псевдослучайного числа - почти всегда плохая идея, даже для не криптографических целей. Что если разрешение временной метки указано в секундах, а вы создаете «file. $ Random» дважды в секунду? К сожалению! ... Кроме того, вы никогда не знаете, когда кто-то собирается использовать вашу GetRandom()функцию, где хороший prng имеет значение, поэтому лучше, если это возможно, получить его с самого начала (а это почти всегда возможно!)
Martin Tournoij
Я не знаю, каково качество $RANDOM, но если это плохой PRNG, то это не повод использовать еще более слабый PRNG :-) Вместо этого, обновите его до лучшего PRNG! Насколько я знаю, /dev/urandomон доступен на всех платформах, где bashон широко доступен, поэтому я не вижу причин не использовать его.
Мартин Турной,
1
Я не знал о $RANDOM. Похоже, очень хороший маленький инструмент, и, хотя это может быть "RNG бедного человека" (как указывает @Carpetsmoker), он определенно соответствует требованию @ kenorb (который задал вопрос) "легко запоминающимся".
Далкер
4

Вы можете использовать rand()и srand()функцию, при условии , ваш Vim двоичный включает патч 8.1.2342 .


Например, для генерации 10 случайных чисел, разделенных символами новой строки:

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

Чтобы сгенерировать 10 случайных чисел, все уступающие 100:

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

Чтобы сгенерировать 10 случайных алфавитных строк из 5 символов:

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")

Для генерации 10 последовательностей из 5 случайных слов:

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]
user938271
источник
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будет то же самое, придется проверить xrangeи random.sample).
Муру
@Carpetsmoker аааа, опечатка. Скобка после 60 должна быть после 10000. И xrangeне в Python3, потому что rangeэто эквивалентно (ни один из них фактически не создает список, в отличие от rangePy2).
Муру
@Carpetsmoker И последнее отличие состоит в том, что mapв Py3 возвращается итеративный, а не список, поэтому будет использоваться последняя строкаlist(map(str, random.sample(range(10000), 60)))
muru
Хорошо, я позволил себе отредактировать ваше сообщение с некоторыми (незначительными) изменениями, чтобы сделать его совместимым с Python 2 и 3 ...
Мартин Турной