Jak wygenerować losowe liczby?


23

Chciałbym wygenerować jedną lub kilka liczb losowych oddzielonych nową linią.

Jak można to zrobić?


1
Czysty vim? Lub powiedzmy za pomocą :python?
— muru

Preferowany jest czysty vim, ale jeśli nie jest wbudowany, każda łatwa do zapamiętania metoda jest w porządku.
— kenorb

Odpowiedzi:


20

Nie ma do tego wbudowanej funkcji, więc musisz użyć czegoś zewnętrznego.

Powłoka UNIX ( /bin/sh)

Powołanie:

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

z system()jest dobrym sposobem. Możesz uzyskać tylko liczby, zastępując trje grep:

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

Możesz użyć tego w Vimie tak:

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

Liczba 15 to liczba liczb, które chcesz (odpowiednio dostosuj). Powinno to działać w systemach Linux, BSD, OSX i innych systemach UNIX. To nie będzie działać na MS Windows.

Zobacz także mój post na blogu „ Generuj hasła z wiersza poleceń ” (istnieje wiele złych rozwiązań tego problemu).

Rubin

Ruby jest prawdopodobnie najlepszym wyborem, ponieważ skrypty Ruby wydają się być nieco bardziej popularne niż skrypty w języku Python. Uzyskanie losowej liczby jest łatwe:

:ruby puts Random.rand(10)

Lub zdobyć 15 numerów:

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

Pyton

Możesz użyć losowego modułu; aby uzyskać pojedynczy numer:

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

Lub 15 liczb:

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

Powinno to działać zarówno w Pythonie 2, jak i 3.

Windows PowerShell

Możesz użyć, Get-Random aby uzyskać losową liczbę:

:echo system('Get-Random')

Windows cmd.exe

Windows 7 i nowsze wersje powinny być dostarczane z programem PowerShell, ale jeśli chcesz uzyskać maksymalną kompatybilność, możesz użyć cmd.exe. Ma specjalną zmienną %RANDOM%:

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

Uwaga: To nie jest bardzo losowe! , wykorzystuje czas (!)


Zauważ, że nie musisz używać powiązań Ruby lub Python, aby korzystać z rozwiązań Ruby lub Python; możesz także utworzyć osobny skrypt i wywołać go za pomocą system("python -c '...'")(oczywiście wymaga to zainstalowania Ruby / Pythona.


Zamiast tr -d '[:space:]', może tr -cd '[:digit:]'dla filtra grep?
— muru

@muru Nie jestem pewien, czy będzie działał na OSX, dlatego go nie użyłem ... W ten sposób liczby są oddzielane przez nowy wiersz, tak jak poprosił OP ...
— Martin Tournoij

Jeśli tak jest ... GNU bije BSD. : P
— muru

Można również użyć powłoki (systemu) do wprowadzania liczb losowych, tj. :r! hexdump -n $((3*4)) -e '"%d"' /dev/urandomWygenerowałby 3 liczby całkowite ze znakiem losowym .
— HAL 9001,

1
@kenorb Spowoduje to prawidłowe użycie powłoki do wprowadzenia 3 losowych liczb całkowitych ze znakiem::r! hexdump -n $((3*4)) -e '"\%d\n"' /dev/urandom
— HAL 9001

12

Oto czyste rozwiązanie vimscript . Nie stworzyłem go, opracował go Charles E. Campbell. Można znaleźć repo GitHub z jego kod tutaj .


Algorytm wykorzystuje 3 nasiona wygenerowane przy starcie Vima i generuje pseudolosową liczbę na podstawie obliczeń i permutacji zastosowanych do nasion:

" 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

Zakres zmiennych jest zadeklarowany jako globalny, ponieważ są używane przez funkcję generatora, ale może być ograniczony do skryptu ( s:)

A oto funkcja generatora:

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

Repozytorium obejmuje następujące funkcje:

  • „Losowa” inicjalizacja nasion;
  • Sposób na odczyt niektórych nasion zdefiniowanych przez użytkownika z pliku tekstowego;
  • Pseudolosowy generator
  • Kilka losowych funkcji:
    • Funkcja generująca liczbę losową w zakresie
    • Funkcja rzutu kostką
    • Funkcja losowego zamiany listy kolejnych liczb całkowitych

Oto szybki test, który napisałem, aby przetestować generator: Wygenerowałem 1000000 liczb od 0 do 9 i policzyłem liczbę wystąpień każdej liczby tutaj są wyniki:

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

Jak widać, generacja wydaje się być dobrze rozproszona. Zdaję sobie sprawę, że w dużej mierze nie wystarcza to do przetestowania generatora losowego, więc spróbuję przeprowadzić dodatkową analizę, jeśli będę miał trochę wolnego czasu.


7

Jest to metoda znaleźć w vim-randomtag wtyczki, która jest oparta na czytanie ... aktualne w czasie mikrosekund, użyteczny gdy chcesz po prostu jakiś numer, nie przejmował się przypadkowości jakości lub wątpliwości związanych z bezpieczeństwem itp .:

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

4

Vim nie oferuje natywnego generatora losowego, jednak jeśli kompilujesz vima z Pythonem, następująca metoda doda losową cyfrę na końcu twojej linii:

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

Uwaga: Aby sprawdzić, czy Twój vim obsługuje Python, spróbuj: :echo has('python')(1 na yes).

Możesz także użyć powłoki, która oferuje $RANDOMzmienną (działa z bash / ksh / zsh), która zwraca pseudolosowy (0-32767), na przykład:

:r! echo $RANDOM

lub:

:put =system('echo $RANDOM')

lub:

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

W systemie Windows musisz mieć zainstalowany Cygwin / MSYS / SUA lub użyć %RANDOM%zmiennej, jak sugeruje Carpetsmoker .

Jeśli nie masz dostępu do powłoki i Pythona, tak jak w celu obejścia tego problemu, użyj kilku ostatnich cyfr z bieżącego znacznika czasu, na przykład:

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

Uwaga: Jeśli używasz go dość często, napisz prostą funkcję, która będzie return reltimestr(reltime())[-4:].

Uwaga: Powyższe metody zwracają tylko pseudolosowe liczby całkowite, których nie należy używać do generowania klucza szyfrowania.


Aby dodać więcej liczb losowych, naciśnij, @:aby powtórzyć polecenie ponownie. Lub przedrostek z liczbą (podobną 10@:), aby dodać znacznie więcej liczb losowych oddzielonych nowymi wierszami.


Związane z:


Współpracuje także z zsh, ale nie z sh, dash, fish, csh, lub tcsh... można użyć :r! bash -c 'echo $RANDOM'...
— Marcina, Tournoij

„zwróć kilka ostatnich cyfr z bieżącego znacznika czasu” -> To nie jest przypadkowe. Wykorzystanie czasu na uzyskanie pseudolosowej liczby jest prawie zawsze złym pomysłem, nawet do celów innych niż szyfrowanie. Co jeśli rozdzielczość znacznika czasu jest wyrażona w sekundach, a „plik. $ Random” zostanie utworzony dwa razy na sekundę? Ups! ... Plus, nigdy nie wiesz, kiedy ktoś ma zamiar korzystać z GetRandom()funkcji gdzie dobry PRNG robi sprawa, więc lepiej po prostu zrobić to dobrze od samego początku, jeśli to możliwe (i to prawie zawsze możliwe tutaj!)
— Martin Tournoij

Nie wiem, jaka jest jakość $RANDOM, ale jeśli jest to zły PRNG, to nie jest powód, aby używać jeszcze gorszego PRNG :-) Zamiast tego, uaktualnij do lepszego PRNG! O ile mi wiadomo, /dev/urandomjest dostępny na wszystkich platformach, na których bashjest powszechnie dostępny, więc nie widzę powodu, aby go nie używać.
— Martin Tournoij

1
Nie wiedziałam o tym $RANDOM. Wydaje się, że jest to bardzo miłe, małe narzędzie i chociaż może to być „biedny człowiek RNG” (jak wskazuje @Carpetsmoker), zdecydowanie pasuje do wymagania @ kenorb (który zadał pytanie) „łatwej do zapamiętania”.
— Dalker

4

Możesz używać funkcji rand()i srand(), pod warunkiem, że twój plik binarny Vim zawiera łatkę 8.1.2342 .


Na przykład, aby wygenerować 10 liczb losowych oddzielonych znakami nowej linii:

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

Aby wygenerować 10 liczb losowych o wartości mniejszej niż 100:

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

Aby wygenerować 10 losowych ciągów alfabetycznych po 5 znaków:

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

Aby wygenerować 10 losowych słów (wziętych z pliku słownika /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")

Aby wygenerować 10 sekwencji 5 losowych słów:

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

Aby wygenerować losowy UUID w wersji 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], '')

Aby zastosować losowy schemat kolorów:

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

3

Nie sądzę, żeby w Vimscript była natywna funkcja dla liczb losowych.

Sposób użycia :python(użyj go w funkcji, być może z 10000 i 60 zastąpionymi parametrami):

: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

Zobacz moją odpowiedź na temat tworzenia skrzynki w vimie przez Pythona, aby uzyskać szybkie wprowadzenie do skryptów Pythona w Vimie.

Ponieważ vim.current.bufferjest to lista ciągów, możemy przypisać do niej listę ciągów tak, jak w Pythonie. random.sampleto po prostu najprostszy sposób na uzyskanie listy losowych liczb całkowitych w Pythonie.


@Carpetsmoker random.samplenaprawia tylko dwa argumenty w Pythonie 2, strjest wbudowaną funkcją do konwersji rzeczy na ciągi. Pozwól, że sprawdzę ekwiwalenty Py3 ( strbyłoby to samo, będę musiał sprawdzić xrangei random.sample).
— muru

@Carpetsmoker aargh, literówka. xrangeNawias po 60 powinien być po 10000. Nie ma go w Python3, ponieważ rangejest równoważny (w rzeczywistości żaden nie tworzy listy, w przeciwieństwie rangedo Py2).
— muru

@Carpetsmoker I ostatnia różnica polega na tym, że mapw Py3 zwraca iterowalną, a nie listę, więc użyje ostatniej liniilist(map(str, random.sample(range(10000), 60)))
— muru

Ok, pozwoliłem edytować swój post z kilkoma (drobnymi) zmianami, aby był kompatybilny zarówno z Pythonem 2, jak i 3 ...
— Martin Tournoij
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.