Генератор случайных паролей


40

Сервер домена требует, чтобы все сотрудники имели надежный случайный пароль, соответствующий следующим правилам:

  • Ровно 15 символов.
  • Только вводимые с клавиатуры символы (как показано в коде типа ниже). Обучение продажам использовать коды ALT + NUMPAD не допускается.
  • Как минимум 1 строчная буква: abcdefghijklmnopqrstuvwxyz
  • Как минимум 1 заглавная буква: ABCDEFGHIJKLMNOPQRSTUVWXYZ
  • Минимум 1 цифра: 0123456789
  • Как минимум 1 символ: `~!@#$%^&*()_+-={}|[]\:";'<>?,./

Для этого ИТ-отдел поручил и будет распространять генератор случайных паролей среди всех сотрудников. Все сотрудники должны будут использовать генератор случайных паролей. Требования к генератору случайных паролей, в дополнение к ограничениям пароля выше:

  • Он должен быть в состоянии генерировать все перестановки всех допустимых символов.
  • Он должен отображать сгенерированный пароль на экране.
  • Код должен быть как можно меньше (в байтах).

Пожалуйста, отправьте предложенное решение в течение следующей недели.


10
Вам также следует потребовать, чтобы все разрешенные пароли появлялись с одинаковой вероятностью (в противном случае я могу просто составить список из 30 символов с разрешенными символами, перемешать его и дать первые 15 пар)
Мартин Тома

@ лось, согласился. Я добавил новое правило.
Hand-E-Food

22
ИТ-специалисты должны быть уволены или, по крайней мере, лучше образованы: если вы генерируете пароли случайным образом, то ограничение набора допустимых паролей теми, которые содержат хотя бы один символ из каждой категории, фактически ослабляет пароли, поскольку уменьшает размер паролей. допустимое множество. И наши программы были бы намного проще, если бы нам не нужно было это проверять ... Хорошо, не изменяйте конкурс после того, как поступило так много заявок; это хорошо, как вызов.
MvG

10

1
Вы действительно не ответили @moose, требуя, чтобы все пароли были генерируемыми. Они должны появиться с равной вероятностью.
Этан Болкер

Ответы:


29

Математика (18)

Позвольте мне немного обмануть

= 15char ASCII pwd
&(^F7yP8k:*1P<t

PS не безопасность :)


6
Где код?
DavidC

11
Гарантируется ли это как минимум по одному требованию каждого из классов символов ?
Hand-E-Food

3
@ Hand-E-Food Да, это так! Если вы посмотрите на интерпретацию, то увидите: длина пароля 15, требуются буквы нижнего регистра, требуются буквы верхнего регистра, требуются цифры, требуются специальные символы.
ибельтуков

6
+1 Умный, но подлый.
DavidC

10
Я знал, что у Mathematica есть функция для всего, но это ?
Конрад Боровски

13

Рубин, 74 69 байт

Просто случайный выбор из диапазона ASCII 33 - 126, пока все классы символов присутствуют:

$_=[*?!..?~].sample(15)*''until~/\d/&&~/[a-z]/&&~/[A-Z]/&&~/\W|_/
p$_

Рубин, 39 байт

Используя умное открытие лося:

p"0123abcdABCD-+/<".chars.sample(15)*''

Изменить, чтобы удовлетворить толпу:

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

(..) все перестановки всех допустимых символов

«Перестановка». Там нет перестановок допустимых символов, которые соответствуют остальным правилам, потому что любая перестановка набора допустимых символов равна длине самого набора допустимых символов (в то время как пароль должен иметь длину 15 символов). И нет никаких повторений в перестановке. Однако моя первая запись все еще более «случайна», чем многие из других хорошо проголосовавших ответов здесь.

Тем не менее, здесь у вас есть это. Позволяет повторения символов и подчеркивания:

Рубин, 77 байт

$_=([*?!..?~]*15).sample(15)*''until~/\d/&&~/[a-z]/&&~/[A-Z]/&&~/\W|_/
puts$_

Я также использовал putsвместо pэтого, потому что pпечатает строку, заключенную в «кавычки», и некоторые символы экранируются обратной косой чертой.

Рубин, 70 байт

Как указывает Ventero, ~может быть пропущен перед регулярными выражениями и printможет быть заменен puts$_. Но с ужасным выводом это может привести к тому, что вы также можете распечатать все отклоненные пароли, сжав их в одну строку:

puts$_=([*?!..?~]*15).sample(15)*''until/\d/&&/[a-z]/&&/[A-Z]/&&/\W|_/

объяснение

Как просили. $_это полумагическая переменная, которая содержит последнюю строку, прочитанную из ввода - так что вам не всегда нужно ее хранить, как это . Здесь, однако, мы используем его из-за другого свойства, а именно, что ~оператор применяет регулярное выражение непосредственно к нему, трюк, который я впервые узнал с помощью chron . Я заменил использование all, но это должно быть довольно легко понять, если вы получите остальное ( см. Документы ).


2
Не могли бы вы немного объяснить свой код? Что делает .all?{|r|~r}? Что делает $_=?
Мартин Тома

3
Пример строки умный и все такое, но я думаю, что он нарушает «Он должен быть в состоянии генерировать все перестановки всех допустимых символов». Нигде не говорится, что пароль может содержать рекламу только в том, что касается букв. Если z является разрешенным символом, должна быть вероятность> 0, что z находится в пароле.
nitro2k01

1
Есть ли \Wв Ruby , включают подчеркивание _? В большинстве диалектов регулярных выражений я знаю, что это не так. И если ваш код не может сгенерировать пароли, в которых _единственным не алфавитно-цифровым символом является один, то это нарушит одно требование. Второй подход, очевидно, нарушает это требование, но я думаю, что он не был правильно сформулирован в то время.
MvG

1
@MvG: Ты прав. \Wне содержит подчеркивания в Perl-совместимом RegEx ( источник ).
Мартин Тома

1
Кроме того, на ваше решение влияет та же проблема @moose, что и у меня с Python: sampleне повторяет элементы, поэтому пароли с повторяющимися элементами не могут быть сгенерированы вашим кодом. Можете ли вы исправить эти две проблемы, чтобы ваш ответ соответствовал вопросу? Видя, что ваше решение является ведущим, за исключением Wolfram Alpha, было бы неплохо увидеть, сможете ли вы соответствовать и при этом сохранять лидерство. Я думаю, это не должно быть слишком сложно.
MvG

12

Java 8 - 354 329 319 275 267 символов

Просто для удовольствия, используя лямбды с Java 8 - каждый возможный вывод имеет одинаковую вероятность быть найденным.

Он использует тот факт, что разрешенные символы имеют последовательные коды ASCII, от 33 до 126.

class A {
    //flags for, respectively, small caps, large caps, digits, punctuation
    static int a, A, d, p;

    public static void main(String[] x) {
        String s;
        do {
            //Using special String constructor that takes an int[]
            s = new String(new java.util.Random().ints(15, 33, 127)
                                .toArray(),
                           0, 15);
            a = A = d = p = 0;
            s.chars()
                .map(c ->
                      c > 96 & c < 123 ? a = 1
                    : c > 64 & c < 90  ? A = 1
                    : c > 47 & c < 58  ? d = 1
                    : (p = 1))
                .min();
        } while (a + A + d + p < 4);
        System.out.println(s);
    }
}

Образец вывода:

.*;Tm?svthiEK`3  
o.dzMgtW5|Q?ATo  
FUmVsu<4JF4eB]1

Сжатая программа:

class A{static int a,A,d,p;public static void main(String[]x){String s;do{s=new String(new java.util.Random().ints(15,33,127).toArray(),0,15);a=A=d=p=0;s.chars().map(c->c>96&c<123?a=1:c>64&c<90?A=1:c>47&c<58?d=1:(p=1)).min();}while(a+A+d+p<4);System.out.println(s);}}


Как насчет while(a+A+d+p<4)вместе с a|=1вместо a++? Или используйте битовые маски, то есть такие вещи, как a|=1сквозные a|=8, с a<15условием цикла. Это сохраняет еще 13 символов, если я посчитал правильно.
MvG

@MvG хороший момент - сделал что-то подобное, сохранив пару дополнительных символов, я считаю.
assylias

@MvG И использование new String(int[],int,int)сохраняет еще 40 с лишним символов!
assylias

8

Python 2.X + 3.X (229 символов): генерировать и заменять

идея

  1. Сначала составьте список из 15 разрешенных символов
  2. Заменить случайную позицию r случайной цифрой
  3. Заменить случайную позицию sнаs != r , по заглавной букве
  4. То же самое для строчных букв и символов, как в 2 и 3.

Код

from random import randint as r, shuffle as s
a=list(range(15))
p=a[:]
for i in range(15):
    a[i]=chr(r(32,126))
s(p)
a[p.pop()]=chr(r(48,57))
a[p.pop()]=chr(r(65,90))
a[p.pop()]=chr(r(97,122))
a[p.pop()]=chr(r(33,47))
print(a)

Python 2.X + 3.X (194 символа): создать и проверить

import random
from re import search as s
p=''
while not all([s("\d",p),s("[a-z]",p),s("[A-Z]",p),s("[\W_]",p)]):
 p=str(map(chr,[random.choice(list(range(33,127))) for i in range(15)]))
print(p)
  • Спасибо MvG, который сказал мне это \uи\l не существует в регулярных выражениях Python.
  • Спасибо grc, который сказал мне, что random.sampleэто без замены, чтобы получить все возможные разрешенные пароли, нам нужна выборка с заменой.

Использование недостатка в описании проблемы

В настоящее время описание проблемы не требует, чтобы каждый символ / цифра появлялся с одинаковой вероятностью. С помощью следующего решения вы не можете делать какие-либо предположения об одном символе и / или позиции. Но вы можете сделать это с несколькими.

Python 2.X + 3.X (62 символа)

from random import sample
print(sample("0123abcdABCD-+/<",15))

Спасибо Даниеро за идею использовать образец.


Очень плавный поиск недостатка! Я подключил это, но бонусные баллы за его идентификацию. :-)
Hand-E-Food

Ваш ген и чек похож на мой подход. Из любопытства: где это \lи так далее для регулярных выражений Python? Не вижу этого в ссылке . Мой Python 3.3.3 даже не примет "\u". Они str(…)не объединяют буквы в 3.3.3 или 2.7.6. Одно из предложений для optmization: all(s("\\"+i,p)for i in "dluW").
MvG

random.sampleвыбирает элементы без замены, поэтому не все пароли возможны.
ГК

@MvG: Спасибо. Я только что видел это \uи \lтолько для vim.
Мартин Тома

7

Bash на * NIX (109)

while ! grep -Pq [A-Z].*[a-z].*[0-9].*[\\W_]<<<$a$a$a$a
do a=`tr -dc !-~</dev/urandom|head -c15`
done
echo $a

Для правильной работы $aне должен быть установлен действительный, но неслучайный пароль заранее. Если вы хотите включить a=и разрыв строки вперед, это еще три символа, но это позволяет вам запускать эту вещь несколько раз. Вы также можете заменить все новые строки на; чтобы у вас была однострочная которую вы можете выполнять так часто, как пожелаете.

Кроме того, вы должны были установить LC_ALL=Cили не устанавливать какие-либо переменные среды, зависящие от локали ( LANGиLC_CTYPE зависящие от в частности), поскольку диапазоны символов зависят от порядка сопоставления, равного порядку ascii.

/dev/urandomявляется источником случайных байтов. !-~это диапазон всех допустимых символов, как указано в вопросе. tr -dcудаляет все символы, не перечисленные в следующем аргументе. headзанимает 15 из оставшихся символов. grepпроверяет, встречается ли каждый из требуемых видов хотя бы один раз. Его ввод состоит из четырех копий кандидата, поэтому порядок символов не имеет значения, поэтому все возможные пароли имеют шанс быть выбранными. -qК ГРЭП выход подавляет.

По неизвестным причинам, /dev/randomа не /dev/urandomпринимает возраст. Кажется, энтропия довольно быстро исчерпала себя. Если вы cdв/dev , вы можете избежать еще несколько байт, но чувствует себя немного как обман.

Python 2 (138)

import re,random
a=''
while not re.search('[A-Z].*[a-z].*[0-9].*[\W_]',a*4):
 a=''.join(random.sample(map(chr,range(33,127))*15,15))
print a

Чтобы сделать код читабельным, я добавил новую строку и отступ после цикла, который не является необходимым и который я не учел.

По сути, это та же идея, что и в версии bash. Случайный источник здесь random.sample, который не будет повторять элементы. Чтобы противостоять этому факту, мы используем 15 копий списка допустимых букв. Таким образом, любая комбинация все еще может иметь место, хотя повторяющиеся буквы встречаются реже. Но я решил считать это особенностью, а не ошибкой, поскольку вопрос не требовал равной вероятности для всех перестановок, только для возможности.

Питон 3 (145)

import re,random
a=''
while not re.search('[A-Z].*[a-z].*[0-9].*[\W_]',a*4):
 a=''.join(random.sample(list(map(chr,range(33,127)))*15,15))
print(a)

Один перевод строки и один отступ снова не учитываются. Помимо некоторых накладных расходов на синтаксис, специфичных для Python-3, это то же решение, что и для Python 2.

JavaScript (161)

a=[];for(i=33;i<127;)a.push(s=String.fromCharCode(i++));
while(!/[A-Z].*[a-z].*[0-9].*[\W_]/.test(s+s+s+s))
for(i=0,s="";i<15;++i)s+=a[Math.random()*94|0];alert(s)

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

R (114)

s<-""
while(!grepl("[A-Z].*[a-z].*[0-9].*(\\W|_)",paste(rep(s,4),collapse="")))
 s<-intToUtf8(sample(33:126,15,T))
s

Разрыв строки и отступ внутри цикла добавлены, но не учитываются. Если вам это нравится, вы можете снова переместить это в одну ;строку.


Ха! Я как раз собирался указать, что вы могли бы использовать greplв своем коде R. Если бы я только думал повторить тестовый пароль четыре раза, чтобы вы могли выполнить все проверки за один раз. И вы знаете, если бы я только подумал о sampleи intToUtf8. Тем не менее, вам нужно добавить replace=TRUE(или, точнее, просто добавить ,T) к вашему образцу метода, чтобы убедиться, что вы получаете все возможные пароли.
AmeliaBR

@ AmeliaBR: Вы правы, исправили эту replace=Tошибку, спасибо за указание на это. Поиск intToUtf8по угадыванию вероятных имен с завершением табуляции занял у меня довольно много времени; Я знал, что такая функция должна существовать, но более распространенные имена, такие как chrи так далее, не использовались.
MvG

@MvG: я не понимаю, почему твой код Python заканчивается вообще. Зачем тебе это *4? Я думал, что ваше регулярное выражение будет соответствовать любой строке, то есть сначала одна заглавная буква, потом что-нибудь, потом одна строчная буква, чем что-либо ... что я ошибся?
Мартин Тома

@moose: Как вы уже заметили, мое регулярное выражение проверяет необходимые категории в определенном порядке. Но, взяв объединение четырех копий текущего кандидата, я могу гарантировать, что порядок больше не имеет значения: даже если мой пароль - это символы, за которыми следуют цифры, за которыми следуют строчные и прописные буквы, совпадение все равно будет. Единственный способ, которым совпадение может потерпеть неудачу - это отсутствие какой-либо категории. Также обратите внимание, что я этого re.searchне делаю re.match, поэтому регулярное выражение может совпадать где угодно в пароле кандидата. Это объясняет, почему это закончится в конечном счете?
MvG

Ах, я не заметил, что вы используете re.searchвместо re.match. Что объясняет его. Но я все еще думаю, что вам не нужно *4. Спасибо за объяснение (+1)
Мартин Тома

7

C # ( сжатые 123 - 139, 103 - 127 символов):

Использование совершенно адекватного метода каркаса в System.Web.dll:

class P
{
    static void Main()
    {
        Console.WriteLine(System.Web.Security.Membership.GeneratePassword(15, 1));
    }
}

Уплотненный:

class P{static void Main()
{Console.WriteLine(System.Web.Security.Membership.GeneratePassword(15,1));}}

Пример:

b+m2ae0K:{dz7:A

В качестве альтернативы, возьмите значение второго параметра ( int numberOfNonAlphanumericCharacters) из командной строки:

class P
{
    static void Main(string[] a)
    {
        Console.WriteLine(System.Web.Security.Membership.GeneratePassword(15, int.Parse(a[0])));
    }
}

3
GeneratePasswordне поддерживает полный набор символов, указанный в вопросе. Также я не нашел никаких гарантий относительно минимального количества вхождений каждой категории персонажей.
MvG

2
Вы можете сжать дальше, используя class Pи string[] a.
d3dave

@MvG, это интересно. Похоже, что он исключает любой символ, который обычно используется для написания акцентированных символов на таких языках, как французский. Вероятно, умный ход. Изменение языка клавиатуры будет достаточно, чтобы заполнить ваш пароль.
Hand-E-Food

5

Р (301 322 персонажа)

Исправление забыл проверить на цифры.

a='abcdefghijklmnopqrstuvwxyz';
f=as.factor(strsplit(paste(a,toupper(a),
    sep="0123456789`~!@#$%^&*()_+-={}|[]\\:\";'<>?,./"),"")[[1]]);
g=gsub("(.):","\\1",levels(q:q:q:q:q:q:q:q:q:q:q:q:q:q:q));
repeat{p=g[runif(1)*length(g)]; 
    if(grepl("[A-Z]",p)&&grepl("[a-z]",p)&&grepl("[0-9]",p)&&grepl("[^A-Za-z0-9]",p))break;};
print(p);

(пробелы добавлены только для ясности).

Создает все возможные 15-символьные перестановки из 94 символов. Затем случайным образом выбирает один, пока не будет соответствовать критериям.

Волшебство в q:qоперации, которая генерирует новый тип данных фактора, который является взаимодействием всех факторов в первом qсписке со всеми факторами во втором списке , с каждой возможной комбинацией этих двух списков, включенных в список " уровни "этого фактора. Взаимодействуйте 15 копий списка разрешенных персонажей, и вы получите (94 ^ 15) возможных уровней.

Пожалуйста, не пытайтесь сделать это дома. Код занимает пару секунд, чтобы выяснить все трехсимвольные перестановки, я действительно не могу себе представить, сколько времени потребуется, чтобы выяснить все 15-символьные перестановки, если ваш компьютер не просто не хватает памяти в То время. Когда я запустил готовый скрипт (трехсимвольный пароль), чтобы проверить его, первым выдаваемым им паролем был «oO =», который, я думаю, подводит итог реакции, которую вы должны иметь на этот код.


У @MvG есть R-скрипт, который гораздо практичнее и короче, хотя и гораздо менее крутой
AmeliaBR

Тем не менее, мне нравится твоя идея. Многие фрагменты кода-гольфа, которые я видел, позволяли специфическим особенностям языка выполнять тяжелую работу. И ваш код, безусловно, делает это для R, с этими взаимодействиями.
MvG

4

Mathematica 170

r=RandomSample;f[i_]:=(FromCharacterCode/@Range@@i);
{t,A,a,n}=f/@{{33,126},{65,90},{97,122},{48,57}};
s=Complement[t,A,a,n];
""<>r[Join[RandomChoice/@{A,a,n,s},r[t,11]],15]

Примеры

"<]} Pg3 / e? 3 + Z ~ Oz"
"X / 8jWe @ f (_x5P: ="
"2wz2VQhtJC? * R7 ^"


4

Python 2,7 (182)

import random as r,string as s
z=r.sample
j=list(z(s.ascii_lowercase,12)+z(s.ascii_uppercase,1)+z(s.digits,1)+z('`~!@#$%^&*()_+-={}|[]\\:";\'<>?,./',1))
r.shuffle(j)
print ''.join(j)

Вы можете получить на 9 цифр меньше, удалив объединение, поскольку это не требуется в описании проблемы. Еще 2 меньше, удалив пробелы.
Мартин Тома

@moose Я убрал пробелы прямо перед тем, как вы прокомментировали :-) Я чувствую, что joinвроде бы там должно быть: Ожидается ли, что пользователи поймут синтаксис списка Python из вывода ['q', 'u', ...]:?
Джонатон Рейнхарт

1
Я думал об удалении печати на всех. Когда важен размер в байтах, они могут жить во времени перфокарты. Таким образом, они могли бы читать память ... просто взглянув на нее. Или они "настоящие программисты": xkcd.com/378
Мартин Тома

1
Если я правильно читаю код, это не соответствует требованию всех перестановок , в нем всегда будет 12 символов нижнего регистра, что делает пароли с несколькими другими группами (например aA$bc1111111111) невозможными.
IQAndreas

1
Я думаю, что в защиту Джонатона правило перестановок было добавлено через 5 минут после его поста.
Hand-E-Food

4

Гольфскрипт (60)

Так как обл. Гольфскрипт отсутствует, и как нуб мне все равно нужна практика :)

[48 10{rand}:r~+65 26r+97 26r+33 15r+11,{;32 96r+}%~]{r}$''+

Он просто строит массив из 4 обязательных + 11 случайных символов и сортирует их в случайном порядке.


+1 за {r}$. Это довольно грязный способ перемешать список - мне это нравится! ;-)
Илмари Каронен

... однако, я не думаю, что это когда-либо может привести, например 0Aa~~~~~~~~~~~~. :-(
Илмари Каронен

3

JavaScript 258 240 233 225

R=Math.random;a=b=>b[b.length*R()|0];for(x=[a(l="abcdefghijklmnopqrstuvwxyz"),a(u=l.toUpperCase()),a(n="0123456789"),a(s="`~!@#$%^&*()_+-={}|[]\\:\";'<>?,./")];15>x.length;x.push(a(l+u+n+s)));alert(x.sort(y=>.5-R()).join(""))

Используя правило, где:

function(x){return x*x}может быть переписан как function(x)x*x. Кажется, работает только для функций, возвращающих значение.

Следующая итерация, уменьшенная x.sort(function().5-R())доx.sort(y=>.5-R())

Следующая итерация уменьшена с помощью жирной стрелки, что, к сожалению, работает только для Firefox 22 и выше.


Хорошее уплотнение! : D
IQAndreas

2

JavaScript (сжато 269 символов)

Для ясности, это код до того, как я его сжал в JS-Fiddle :

var lowerLetters = "abcdefghijklmnopqrstuvwxyz";
var upperLetters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
var numbers = "0123456789";
var symbols = "`~!@#$%^&*()_+-={}|[]\\:\";'<>?,./";
var allCharacters = lowerLetters + upperLetters + numbers + symbols;

String.prototype.randomChar = function() {
    return this[Math.floor(this.length * Math.random())];
}

var minLength = 15;
var result = [];

// Start off by picking one random character from each group
result.push(lowerLetters.randomChar());
result.push(upperLetters.randomChar());
result.push(numbers.randomChar());
result.push(symbols.randomChar());
// Next, pick a random character from all groups until the desired length is met
while(result.length < minLength) {
    result.push(allCharacters.randomChar());
}
result.shuffle(); // Finally, shuffle the items (custom function; doesn't actually exist in JavaScript, but is very easy to add) -> http://stackoverflow.com/questions/2450954/how-to-randomize-shuffle-a-javascript-array
result.join("");

Здесь он сжат до 269 символов ( JS-Fiddle of it ):

l="abcdefghijklmnopqrstuvwxyz";
u=l.toUpperCase();
n="0123456789";
s="`~!@#$%^&*()_+-={}|[]\\:\";'<>?,./";
R=Math.random;

function r(t){
    return t[~~(t.length*R())]
}

for(x=[r(l),r(u),r(n),r(s)];x.length<15;x.push(r(l+u+n+s)));
x.sort(function(){return .5-R()});
alert(x.join(""));

Поскольку я заканчиваю строки точкой с запятой, все удаляемые пробелы игнорировались при подсчете символов, но оставлялись для ясности.
IQAndreas

Что вы подразумеваете под shuffle()«пользовательской функцией». Является ли это частью JavaScript или кода, вам придется написать его самостоятельно?
Hand-E-Food

@ Hand-E-Food Я имел в виду, что он не встроен в JavaScript, и так как все разработчики должны знать, как перетасовывать массив, я чувствовал, что включать в код функцию не нужно. Это доступно в JS-Fiddle, хотя (строка 16).
IQAndreas

1
Суть в том, что он учитывается в счетчике байтов. Но теперь я вижу, что вы реализовали это в компактной версии, поэтому, пожалуйста, игнорируйте меня. :-)
Hand-E-Food

2

Clojure (63):

(->> (map char (range 33 127)) (shuffle) (take 15) (apply str))

Но необходимо улучшить, чтобы убедиться, что он содержит не менее 1 символа каждой категории (верхний, нижний, цифра, символ).


2

В sql-сервере

declare @a nvarchar(28)
set @a='abcdefghijklmnopqrstuvwxyz'
declare @b nvarchar(max)
set @b='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
declare @c nvarchar(max)
set @c='0123456789'
declare @d nvarchar(max)
set @d='~!@#$%^&*()_+-={}|[]\:";<>?,./'

select left(substring(@a,cast(rand()*10 as int),3)+substring(@b,cast(rand()*10 as int),6)+substring(@c,cast(rand()*10 as int),3)+substring(@d,cast(rand()*10 as int),5),15)

Смотрите это в действии - 1

увидеть это в действии - 2


1
У меня проблемы с выполнением последней строки, но, похоже, код не соответствует требованию всех перестановок .
IQAndreas

Ваш код никогда не будет генерировать ни пароль, начиная с которого ~0Aa, ни пароль, bза которым следует a.
Хайнци

@Heinzi: да, я согласен, что все необходимые перестановки не приняты во внимание, он просто отображает 15 длинных символов, случайно выбранных из ... z, A..Z, 0..9,! ... + :(. ..
Вхадалги

2

САС (191)

%macro c(p);compress(p,,"&p")ne''%mend;data x;length p$15;do x=1by 1;do t=1to 15;substr(p,t,1)=byte(ranuni(7)*94+33);end;if %c(kd)and %c(kl)and %c(ku)and %c(ad)then do;put p;stop;end;end;run;

*TQP,(f=h10*)S=

Комментарии / отступ:

%macro c(p); /*compress removes or keeps certain classes of characters*/
  compress(p,,"&p")ne''
%mend;
data x;
length p$15;
do x=1by 1;
    do t=1to 15;
        substr(p,t,1)=byte(ranuni(7)*94+33); /*give it a 33-126, byte discards the noninteger portion rounding down*/
    end;
    if %c(kd)and %c(kl)and %c(ku)and %c(ad)then do; /*k=keep d=digit l/u=lower/upper ad=remove digits and alphas*/
        put p;
        stop;  /*met our requirement, head home*/
    end;
end;
run;

2

PowerShell: 119

Позолоченный код

for(;!($x-cmatch'.*(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[!-/:-@[-`{-~]).*')){$x='';1..15|%{$x+=[char](33..126|random)}}$x

Без гольфа и прокомментировал

# Start for loop definition.
for(
    # Skip variable initialization, start definition of run condition.
    ;
    # Loop runs if $x does not meet complexity requirements.
    # Length requirement is not tested here because it is enforced by the generator later.
    # Much thanks to @VasiliSyrakis for the RegEx help.
    !($x-cmatch'.*(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[!-/:-@[-`{-~]).*')
)
{
    # Reset $x in case the script block has already run.
    $x='';
    # Use ForEach-Object, via the % alias, to run a loop 15 times.
    1..15|%{
        # Append a random ASCII character from 33-126 to $x.
        # Note: Use get-random instead of random for faster performance.
        $x+=[char](33..126|random)
    }
}
# Display $x.
$x
# Variable cleanup - not included in golfed code.
rv x

Я думаю, что это регулярное выражение может сделать его немного короче: ^.*(?=.{15,})(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[!#$%&? "]).*$вы можете сделать одно совпадение с ним, которое будет соответствовать только тогда, когда есть один верхний, нижний, цифровой, символ.
Василий Сиракис

@VasiliSyrakis Ладно, возможно, тебе придется немного пройтись со мной. Не стесняйтесь открыть чат, если вы думаете, что это займет некоторое время. Пара вещей, в которых я запутался: 1.) Я вижу число 15, включенное там. Чтобы убедиться, что строка ровно 15 символов? Если это так, это может быть опущено, поскольку скрипт, естественно, генерирует только 15-символьные строки. 2.) Что вы имеете в виду "будет соответствовать только тогда, когда есть один верхний, нижний, цифра, символ"? Означает ли это, что он будет совпадать только тогда, когда есть только один из них или хотя бы один из них? Бывший сломает вещи.
Изи

Кроме того, ваш RegEx игнорирует порядок символов? Например, если настроить для соответствия 4-символьным строкам, будет ли и то, 1aZ%и другое (p3R? У меня были некоторые трудности с поиском способов сделать это онлайн.
Изи

Протестировал новый RegEx против вывода из моего текущего скрипта. Это не совсем надежно. Код: $x-cmatch'^.*(?=.{15,})(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[!#$%&? "]).*$'Хорошие совпадения: C>suD1?hTwbDx(z j%4O]HyeG|u[U$5 O/rGeD0$hJk=GO/Неудачные совпадения: 3evthX3_X^nBrR` .nA ~ uYzrR4YV-r.u-IjZE48ntQ;HxV
Изи

Как открыть чат?
Василий Сиракис

1

Python 2,7 (149)

from random import*
''.join(map(lambda x:chr(randint(*(x[1]or(32,126)))),sorted(map(None,sample(range(15),15),((48,57),(65,90),(97,122),(33,47))))))

Записано более читаемым (а не исполняемым) способом;

from random import *
''.join(                                          # Concatenate characters to string
  map(                                            # Map all characters using below lambda
    lambda x:chr(randint(*(x[1] or (32, 126)))),  # Map a single range to a random character
                                                  # within a specific range if supplied,
                                                  # otherwise the default "all" range.
    sorted(                                       # After distributing ranges, sort
      map(None,                                   # zip_longest alternative, distributes the
                                                  # required ranges over 4 random positions
        sample(range(15), 15),                    # 0-14 in random order
        ((48, 57), (65, 90), (97, 122), (33, 47)) # The 4 required ranges
      )
    )
  )
)

Довольно прямолинейно и на удивление не намного дольше, чем версия «создать, повторить при сбое матча».


Вы уверены, что это действительно может генерировать все подходящие пароли, в том числе, например 0Aa~~~~~~~~~~~~? (Обратите внимание, что '~' == chr(126).)
Ильмари Каронен

1

PSQL (189)

Похоже, PSQL немного многословен ... :)

SELECT ARRAY_TO_STRING(ARRAY_AGG(CHR((TRUNC((b-a)*RANDOM()+a))::int)ORDER BY RANDOM()),'')FROM(SELECT 32 a,127 b FROM generate_series(1,11)UNION ALL VALUES(48,58),(65,91),(97,123),(33,48))a

SQLfiddle demo .


1

PHP, 235 225

Этот скрипт перемешивает символы, а затем проверяется через RegEx, чтобы убедиться, что пароль надежный (или он регенерирован).

<?php
while(!preg_match('/^(?=.*[A-Z])(?=.*[^A-Za-z])(?=.*[0-9])(?=.*[a-z]).{15}$/',$p)){ $p = substr(str_shuffle('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789`~!@#$%^&*()_+-={}|[]\:";\'<>?,./'),0,15); }
echo $p;

1
Умно, но не позволяет дублировать символы.
Hand-E-Food

1
Вместо while(true) ... if (condition) breakвы можете использоватьwhile (!condition)
Exussum

1

Javascript (209)

r=Math.random;function t(x,y){return String.fromCharCode(Math.floor(y*r()+x))};x=[t(33,14),t(48,10),t(65,26),t(97,26)];for(i=0;i<11;i++)x.push(t(32,95));console.log(x.sort(function(){return r()-0.5}).join(''))

Пол-ungolfed;

// Return a character in the range [x,x+y)
function t(x,y) { return String.fromCharCode(Math.floor(y*Math.random()+x)) }
// Prefill required ranges
x=[ t(33,14), t(48,10), t(65,26), t(97,26)]
// Push 11 totally random (valid) characters
for(i=0; i<11; i++)
  x.push(t(32,95))
// Shuffle and output as string
console.log(x.sort(function(){return Math.random()-0.5})
             .join(''))

1

Perl, 92

Не так лаконично, как ответ на Ruby, но я уверен, что мастер Perl мог бы сделать это еще короче ... Я не слишком доволен всеми m//функциями в конце, но, похоже, работает и должен удовлетворять условиям, чтобы в конечном итоге генерировать все перестановки.

do{$_=join"",map{(map{chr}33..127)[rand 94]}0..14}while!(/[A-Z]/&/[a-z]/&/\d/&/[\W_]/);print

Пример использования:

perl -e 'do{$_=join"",map{(map{chr}33..127)[rand 94]}0..14}while!(/[A-Z]/&/[a-z]/&/\d/&/[\W_]/);print'

Отредактированный , чтобы исправить проверки и изменения [[:punct:]]к [\W_]после MvGs комментариев.


1
Ваша часть генерации хороша, но ваш критерий выбора в условии цикла совершенно неверен: например, пароль из- aaaaaaaaaaaaaaза чего цикл завершится. Вы должны проверить критерии с неслучайными паролями, чтобы убедиться, что они делают то, что вам нужно.
MvG

Действительно, вы правы, я исправил это и сохранил несколько байтов! Благодарность!
Дом Гастингс

1
Вы уверены в этом [[:punct:]]? Думаю, я бы предпочел , which is shorter and of which I'm even more sure that it is correct, at least combined with your диапазон '[\ W_] 33..127`.
MvG

Хороший момент, я думаю, я был обеспокоен тем, что \Wне включал _, но вы абсолютно правы, в этом нет необходимости: gist.github.com/anonymous/8301237 . Спасибо!
Дом Гастингс

1

Java 7 ( 270 234 символов)

Посылка та же самая, что используется @assylias с java 8 (генерируйте случайные пароли до тех пор, пока не получите действительный пароль). Однако вместо использования лямбда-символов пароль генерируется путем итерации массива char и проверяется путем сопоставления с регулярным выражением.

class A {
  public static void main(String [] a) {
    byte[] b = new byte[15];
    String s;
    do {
      new java.util.Random().nextBytes(b);
      s = new String(b);
    } while(!s.matches("(?=.*?[a-z])(?=.*?[A-Z])(?=.*?\\d)(?=.*?[!-/:-@\\[-`]).*"));
    System.out.println(s);
  }
}

Минимизированный код:

class A {public static void main(String[] a){byte[] b=new byte[15];String s;do{new java.util.Random().nextBytes(b);s=new String(b);}while(!s.matches("(?=.*?[a-z])(?=.*?[A-Z])(?=.*?\\d)(?=.*?[!-/:-@\\[-`]).*"));System.out.println(s);}}

1

Powershell


Версия с одним вкладышем (143 байта)

sal g random;1..11|%{$P+=[char](33..126|g)};(65..90|g),(97..122|g),(48..57|g),(33..47+58..64+123..126|g)|%{$P=$P.insert((1..11|g),[char]$_)};$P

Мини-версия (146 байт)

sal g random
1..11|%{$P+=[char](33..126|g)}
(65..90|g),(97..122|g),(48..57|g),(33..47+58..64+123..126|g)|%{$P=$P.insert((1..11|g),[char]$_)}
$P

Читаемая версия (860 байт)

function pwgen {

    # Fulfill Upper,Lower,Digit,Symbol requirement by predefining ASCII ranges for each
    # These will be added into the string beginning at line 24

    [array[]]$symbolrange = (33..47),(58..64),(123..126)

    [char]$upper = (get-random (65..90))
    [char]$lower = (get-random (97..122))
    [char]$digit = (get-random (48..57))
    [char]$symbol = $symbolrange | get-random

    [char[]]$requirement = $upper + $lower + $digit + $symbol

    # Create the first 11 characters using any ASCII character between 32 - 126

    foreach ($number in (1..11)) {
        [string]$pass += [char](get-random (33..126))
    }

    # Insert each requirement character at a random position in the string

    foreach ($char in $requirement) {
        [string]$pass = $pass.insert((Get-Random (1..11)),$char)
    }

    return $pass
}

Благодарим Исзи за различные советы по сокращению кода.


1
Это не распространяется на все перестановки. Например, abcd1234ABCD{|}~никогда не появится, потому что $symbolхотя бы один из символов находится между ASCII 33 и 47.
Hand-E-Food

Dangit! Вы должны указать на мою лень !? Шучу ... Я редактировал это сейчас. Я также заставил каждый символ «требования» переходить к отдельному индексу в строке, вместо того, чтобы объединять все четыре в одном индексе. Теперь, если бы я только мог сократить это ...
Василий Сиракис

Может быть, есть какая-то причина, по которой вы не можете сбрить еще пару символов, сокращаясь $SRдо $Q?
Изи

Вы также должны быть в состоянии сократить такие вещи , как (g(65..90))вниз к 65..90|g'. And change the foreach` заявлению на foreach-objectпетли с использованием %псевдонима. Пример: foreach($N in (1..11)){... }должно быть выполнимо , как 1..11|%{... }. Я почти уверен, что возможны другие варианты оптимизации, но на самом деле я имею в виду совершенно иную реализацию, которую планирую попробовать позже.
Изи

Хорошие советы :) Я сократил его до 213 байт, если вынул возврат каретки и заменил точку с запятой.
Василий Сиракис

1

Фактор, 196 символов

Тот же алгоритм, что и в MvG и Moose's. Это не самый короткий, но должен соответствовать всем (текущим) критериям в вопросе:

USING: io kernel math pcre random sequences sequences.repeating ;
[ 15 94 random-integers [ 33 + ] "" map-as dup 60 cycle
"[A-Z].*[a-z].*[0-9].*[\\W_]" findall { } = not ] [ drop ] until print

Возможно, я неверно истолковываю регулярное выражение, но я думаю, что что-то подобное ~{}|1234abcdABCDпотерпит неудачу в регулярном выражении.
Hand-E-Food

1
Нет, это будет работать "~{}|1234abcdABCD" 60 cycle "[A-Z].*[a-z].*[0-9].*[\\W_]" findall empty? not => t
Бьорн Линдквист

Я верю вашему слову за это. :-)
Hand-E-Food

1

C - 154 символа

char p[16],c,f,w;main(){srand(time());while(f^15){c=p[15]=f=0;while(c^15){w=33+rand()%94;f|=w
>96&&w<123?1:w>47&&w<59?2:w>64&&w<91?4:8;p[c++]=w;}}puts(p);}

Как я ненавижу srand()? Позвольте мне сосчитать пути.


1

Хаскелл, 192

import System.Random
main=getStdGen>>= \g->(print.(take 15))$until((\x->all(any(`elem`x))[['a'..'z'],['A'..'Z'],['0'..'9'],['!'..'/']++":;<=>?@[\\]^_`{|}~"]).(take 15))tail$randomRs('"','~')g

Напечатанная строка имеет кавычки и экранирует символы обратной косой черты и кавычки; если это неприемлемо, printможно заменить еще putStrLnна 3 байта. Вот более читаемая версия:

import System.Random

main = do
    g <- getStdGen
    let chars = randomRs ('"', '~') g
    let password = take 15 $ until (hasChars.(take 15)) tail chars
    print password

hasChars :: String -> Bool
hasChars x = all (any (`elem` x)) $
    [ ['a'..'z']
    , ['A'..'Z']
    , ['0'..'9']
    , "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"
    ]

Это довольно просто, он просто создает бесконечный / ленивый список случайных символов ASCII в диапазоне '!'до '~', затем отбрасывает первый элемент, пока первые 15 символов не получат хотя бы один символ из каждой строки обязательных символов.


1

Excel VBA, 209 байт

For i = 1 To 15
x = x + Chr(Int(90 * Rnd + 33))
Next
p = "^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*(_|[^\w])).+$"
With New RegExp
.Pattern = p
Set m = .Execute(x)
If m.Count = 0 Then
MsgBox "redo"
Else
MsgBox x
End If
End With

Произвольно генерирует 15 символов ASCII, поэтому возможны все возможные комбинации. Затем использует шаблон регулярного выражения, чтобы проверить, содержит ли он хотя бы один из каждого критерия.

Если это так, то отображается пароль, если не отображается «Повторить».

Спасибо Барту Кайерсу за шаблон регулярного выражения: https://stackoverflow.com/questions/1559751/regex-to-make-sure-that-the-string-contains-at-least-one-lower-case-char- верхний


0

AutoHotkey 352

global o:={}
loop 4
o[c()]:=o(A_index-1)
loop 11
o[c()]:=o(m(r(),4))
loop 15
s.=o[A_index-1]
msgbox % s
r(){
Random,z
return z
}
m(z,r){
return mod(z,r)
}
c(){
while o[t:=m(r(),15)]!=""
j++
return t
}
o(f){
r0:=48,l0:=10,r1:=97,l1:=l2:=26,r2:=65
r := chr(r%f%+m(r(),l%f%))
if f=3
r:=Substr("``~!@#$%^&*()_+-={}|[]\:"";'<>?,./",m(r(),32)+1,1)
return r
}

Использование - Просто запустите скрипт


0

Python (121 символ)

Использует тот факт, что вы можете умножать списки в Python [1,2,3] * 2, дает [1,2,3,1,2,3]. Импорт случайный. Числа в списке, умноженные на три, являются границами между диапазонами в таблице ascii для необходимых символов, например, [65, 90] отображаются в верхний регистр букв.

print "".join([random.choice([chr(i) for i in range(z[0],z[1])]) for z in [[33,48],[48,58],[58,65],[65,90],[90,123]]* 3])

1
Msgstr "Он должен быть способен генерировать все перестановки всех допустимых символов." Я не думаю, что это так, поскольку диапазоны всегда применяются в одном и том же порядке ...?
Иоахим Исакссон

Вы правы, спасибо. Действительно, я не заметил, что диапазоны должны применяться в случайном порядке, они должны быть перетасованы, я отредактирую это через минуту.
Pawelmhm

Это необходимо включить import randomв код.
Mego

0

PHP 5.5 (230 байт)

echo preg_replace_callback('/./', function ($a)
{
  return chr([rand(33, 126), rand(48, 57), rand(65, 90), rand(97, 122), ord(str_shuffle('`~!@#$%^&*()_+-={}|[]\:";\'<>?,./')[0])][$a[0]]);
}
, str_shuffle(str_pad('1234', 15, 0)));

Или на одной строке (211 байт)

echo preg_replace_callback('/./',function($a){return chr([rand(33,126),rand(48,57),rand(65,90),rand(97,122),ord(str_shuffle('`~!@#$%^&*()_+-={}|[]\:";\'<>?,./')[0])][$a[0]]);},str_shuffle(str_pad('1234',15,0)));
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.