Як генерувати випадкові числа?


23

Я хотів би створити одне або кілька випадкових чисел, розділених новим рядком.

Як це можна зробити?


1
Чистий вим? Або, скажімо, використовуючи :python?
муру

Чистий vim віддав перевагу, але якщо це не вбудований, будь-який легкий запам'ятовується метод чудово.
kenorb

Відповіді:


20

Для цього немає вбудованого засобу, тому вам потрібно буде використовувати щось зовнішнє.

Оболонка UNIX ( /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.

Також дивіться мій пост у веб-журналі " Створення паролів з командного рядка " (для цього існує маса поганих рішень).

Рубін

Рубі, мабуть, наступний найкращий вибір, оскільки сценарії Рубі здаються дещо частішими, ніж сценарії 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 '...'")(очевидно, для цього потрібно встановити рубін / пітон.


Замість 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

Ось чисте вимскриптне рішення. Я його не створив, його розробив Чарльз Е. Кемпбелл. Ви можете знайти репо 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

Як бачимо, покоління, здається, добре розподілене. Я знаю, що цього в основному недостатньо для тестування випадкового генератора, тому я спробую зробити додатковий аналіз, якщо у мене є вільний час.


7

Це метод, знайдений у плагіні vim-randomtag , який ґрунтується на зчитуванні ... мікросекунд поточного часу, який можна використовувати, коли ви просто хочете якусь цифру, вам не дуже важливо якість випадкових випадків або проблеми безпеки тощо.

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

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 .

Якщо у вас немає доступу до оболонки та Python, як для вирішення проблеми, ви використовуєте останні кілька цифр з поточної мітки часу, наприклад:

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

Примітка. Якщо ви використовуєте його досить часто, напишіть просту функцію, яка буде return reltimestr(reltime())[-4:].

Примітка. Вищезазначені методи повертають лише псевдовипадкове ціле число, яке не слід використовувати для створення ключа шифрування.


Щоб додати більше випадкових чисел, натисніть, @:щоб повторити команду ще раз. Або префікс з числом (як 10@:), щоб додати набагато більше випадкових чисел, розділених новими рядками.


Пов'язані:


Вона також працює з zsh, але не з sh, dash, fish, csh, або tcsh... Ви можете використовувати :r! bash -c 'echo $RANDOM'...
Martin Tournoij

"повернути останні кілька цифр з поточної позначки часу" -> Це не випадково. Використання часу для отримання псевдовипадкового числа майже завжди є поганою ідеєю, навіть для некриптових цілей. Що робити, якщо роздільна здатність часової позначки знаходиться в секундах, і ви створюєте "файл. $ Випадковий" двічі за секунду? На жаль! ... Плюс до цього, ви ніколи не знаєте, коли хтось використовуватиме вашу GetRandom()функцію там, де має значення хороший прнґ , тому краще просто отримати це з самого початку, якщо це можливо (і це майже завжди можливо тут!)
Мартін Турной

Я не знаю, що таке якість $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]

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 aargh, друкарня. Кронштейн після 60 повинен бути після 10000. І xrangeне в Python3, тому що rangeвін еквівалентний (жоден фактично не створює список, на відміну від rangePy2).
муру

@Carpetsmoker І остаточна різниця полягає mapв тому, що в Py3 повертається ітерабельний, а не список, тому останній рядок буде використанийlist(map(str, random.sample(range(10000), 60)))
muru

Гаразд, я взяв на себе змогу редагувати вашу публікацію з деякими (незначними) змінами, щоб зробити її сумісною і з Python 2, і з 3 ...
Martin Tournoij
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.