随机密码生成器


40

域服务器要求所有员工都具有严格的随机密码,并遵守以下规则:

  • 恰好15个字符。
  • 只能由键盘输入的字符(如下面的代码类型所示)。禁止教销售人员使用ALT + NUMPAD代码。
  • 至少1个小写字母: abcdefghijklmnopqrstuvwxyz
  • 至少1个大写字母: ABCDEFGHIJKLMNOPQRSTUVWXYZ
  • 至少1个数字: 0123456789
  • 至少1个符号: `~!@#$%^&*()_+-={}|[]\:";'<>?,./

为此,IT已委托并将将“随机密码生成器”分发给所有员工。所有员工都必须使用随机密码生成器。除了上述密码限制之外,Random Password Generator的要求还包括:

  • 它必须能够生成所有允许字符的所有排列。
  • 它必须在屏幕上显示生成的密码。
  • 要求代码尽可能小(以字节为单位)。

请在下周内提交您建议的解决方案。


10
您还应该要求所有允许的密码以相同的概率出现(否则,我可以简单地列出一个30个字符长的列表,其中包含允许的字符,将其随机排列,并给出前15个字符)
Martin Thoma,2014年

@驼鹿,同意。我添加了一条新规则。
Hand-E-Food

22
IT人员应该被解雇,或者至少受过良好的教育:如果您确实随机生成密码,则将允许的密码集限制为每个类别至少包含一个字符的密码实际上会削弱密码,因为这会减小密码的大小。允许的集合。如果我们不必进行检查,我们的程序就会变得容易得多……好吧,在提交了如此多的书后,不要修改比赛;作为挑战很好。
MvG 2014年


1
您并没有要求所有密码都可以生成,因此并没有真正回答@moose。它们应该以相等的概率出现。
伊桑·博克

Answers:


29

Mathematica(18)

让我作弊

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

PS不安全:)


6
代码在哪里?
DavidC 2014年

11
是否可以保证满足每个字符类别的至少一项要求?
Hand-E-Food

3
@ Hand-E-Food是的,是的!如果您看下面的解释,将会看到:密码长度15,要求小写字母,要求大写字母,要求数字,要求特殊字符。
ybeltukov 2014年

6
+1聪明,但偷偷摸摸。
DavidC 2014年

10
我知道数学有一个函数的一切,但这个
Konrad Borowski14年

13

Ruby,74个 69字节

只需从ascii范围33-126随机采样,直到出现所有类别的字符:

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

Ruby,39个字节

使用驼鹿的聪明发现:

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

编辑以满足暴民:

请注意,我第一次发布此规则,规则发生了变化。当时,先前的两个条目都适用于规则。我还想指出,规则的定义还不是很清楚:

(..)所有允许字符的所有排列

“排列”。有没有 排列与规则中其余的规定,因为该组允许任何字符排列是,只要一套允许的字符本身(而密码应该是15个字符)允许的字符。并且在排列中没有重复。但是,我的第一个条目仍然比此处的其他许多受好评的答案更“随机”。

不过,这里有。允许重复字符和下划线:

Ruby,77个字节

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

我还用puts了它p,因为它p打印出了用引号引起来的字符串,并且某些字符以反斜杠转义了。

Ruby,70个字节

正如Ventero所指出的,~可以在正则表达式前面跳过,并print可以替换puts$_。但是,由于输出丑陋,因此您也可能还会打印所有被拒绝的密码,并将其压缩为单行:

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

说明

按照要求。$_是半魔术变量,包含从输入读取的最后一行-因此,您不必总是像这样存储它。但是在这里我们由于另一个属性而使用它,即~运算符直接将正则表达式应用到它,这是我由chron第一次学习的技巧。我替换了的用法all,但是如果您得到其余的内容,则应该很容易理解(请参阅docs)。


2
您能解释一下您的代码吗?怎么.all?{|r|~r}办?怎么$_=办?
Martin Thoma 2014年

3
示例行很聪明,但我认为它违反了“它必须能够生成所有允许字符的所有排列”。它没有说密码只包含字母方面的广告。如果z是允许的字符,则密码中的z应该有> 0的机会。
nitro2k01 2014年

1
\W在Ruby中是否包含下划线_?在大多数正则表达式方言中,我都不知道。而且,如果您的代码无法生成密码,而密码_是唯一的非字母数字符号,那么它将违反一项要求。第二种方法显然违反了该要求,但我想当时措辞不正确。
MvG 2014年

1
@MvG:你是对的。\W在与Perl兼容的RegEx()中不包含下划线。
Martin Thoma 2014年

1
此外,您的解决方案也受到@moose和我在Python中遇到的相同问题的影响:sample不重复元素,因此您的代码无法生成具有重复元素的密码。您可以解决这两个问题以使答案与问题相符吗?除了Wolfram Alpha之外,看看您的解决方案是否是领先的解决方案,很高兴了解您是否能够遵守并保持领先地位。我想应该不会太难。
MvG 2014年

12

Java 8-354 329 319 275 267个字符

只是为了好玩,将lambda与Java 8配合使用-每个可能的输出都有被发现的相同可能性。

它使用以下事实:允许的字符具有从33到126的连续ascii码。

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 2014年

@MvG好点-做了类似的事情,我节省了几个额外的字符。
assylias 2014年

@MvG使用new String(int[],int,int)可以保存另外40多个字符!
assylias 2014年

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

感谢daniero提出使用示例的想法。


非常顺利地发现缺陷!我已经插入了那个,但可以识别它的奖励积分。:-)
Hand-E-Food

您的gen&check与我的方法类似。出于好奇:\lpython regexes 在哪里记录?在参考资料中看不到它。我的Python 3.3.3甚至不接受"\u"。在str(…)不加入任一3.3.3或2.7.6的字母。关于优化的一项建议:all(s("\\"+i,p)for i in "dluW")
MvG 2014年

random.sample选择元素而不进行替换,因此并非所有密码都可用。
grc 2014年

@MvG:谢谢。我刚刚看到了,\u而且\l仅是vim。
Martin Thoma 2014年

7

在* 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或不设置任何特定的语言环境的环境变量(LANGLC_CTYPE特别),因为字符的范围取决于排序顺序等于ASCII顺序。

/dev/urandom是随机字节的来源。!-~是问题中指定的所有允许字符的范围。tr -dc删除所有在其下一个参数中列出的字符。head剩余15个字符。grep检查每种必需种类是否确实至少发生一次。它的输入由候选者的四个副本组成,因此符号的顺序无关紧要,因此所有可能的密码都有可能被选择。该-q到grep来禁止输出。

由于未知的原因,/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个允许的信件清单。这样,每种组合仍然可以发生,尽管带有重复字母的组合出现的频率会降低。但是我决定考虑将此功能作为功能,而不是错误,因为问题并不需要所有排列的均等概率,而仅是可能性。

Python 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 2014年

@AmeliaBR:您是正确的,已修复该replace=T错误,感谢您指出此错误。查找intToUtf8与标签完成猜测可能的名字花了我相当长的时间; 我知道必须存在这样的功能,但是chr没有使用更常见的名称,诸如此类。
MvG 2014年

@MvG:我根本不明白为什么您的Python代码会终止。你为什么需要那个*4?我认为您的正则表达式将匹配任何字符串,该广告首先匹配一个大写字母,然后匹配任何内容,然后匹配一个小写字母……我怎么了?
Martin Thoma 2014年

@moose:正如您已经注意到的,我的正则表达式会按特定顺序检查所需的类别。但是,通过将当前候选人的四份副本串联在一起,我可以确保顺序不再重要:即使我的密码是符号,后跟数字,小写字母和大写字母,也仍然存在匹配项。匹配失败的唯一方法是完全缺少类别。另外请注意,我re.search不是re.match,所以正则表达式可能在候选密码之间是否匹配。这是否解释了为什么最终会终止?
MvG 2014年

啊,我没有注意到您使用re.search代替re.match。这就解释了。但是我仍然认为你不需要*4。感谢您的解释(+1)
Martin Thoma 2014年

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 2014年

2
您可以使用class P和进一步压缩string[] a
d3dave 2014年

@MvG,这很有趣。看起来它不包括通常用法语(如法语)书写带重音符号的任何符号。可能是明智之举。更改键盘语言足以填充您的密码。
Hand-E-Food

5

R(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);

(添加空格仅是为了清楚起见)。

生成94个字符的所有可能的15个字符的排列。然后随机选择一个,直到符合条件。

操作中的魔力在于 q:q,它会生成一个新的因子数据类型,该数据类型是第一个q列表中的所有因子与第二个列表中的所有因子相互作用,这两个列表的每种可能组合都包含在“级别”。交互15个允许的字符列表,您可以获得(94 ^ 15)可能的等级。

请不要在家尝试。该代码需要花费几秒钟来找出所有三个字符的排列,我真的无法想象如果您的计算机不仅仅是内存中的全部用完了,那么找出所有15个字符的排列将花费多长时间。与此同时。当我运行完成的(三个字符的密码)脚本进行检查时,它吐出的第一个密码是“ oO =”,我认为该密码汇总了您对该代码的反应。


@MvG有一个R脚本,它更加实用并且更短,甚至更令人敬畏:codegolf.stackexchange.com/a/17700/12413
AmeliaBR 2014年

不过,我喜欢你的想法。我看到的许多代码片段都使该语言的特定功能起作用。通过这些交互,您的代码当然可以为R做到这一点。
MvG 2014年

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个。
Martin Thoma 2014年

@moose我在您发表评论之前就删除了空格:-)我觉得join这里一定存在:用户应该从输出中理解python列表语法['q', 'u', ...]吗?
Jonathon Reinhart 2014年

1
我考虑过要完全取消打印。当以字节为单位的大小很重要时,它们可能存在于打孔卡时间内。这样,他们可能能够仅通过查看内存来读取内存。还是他们是“真正的程序员”:xkcd.com/378
Martin Thoma

1
如果我正确地阅读了代码,那么这将不能满足所有排列要求,它将始终包含12个小写字符,从而使密码不能包含多个其他组(例如aA$bc1111111111)中的一个。
IQAndreas 2014年

1
在Johnathon的辩护中,我认为排列规则是在他的职务后5分钟添加的。
Hand-E-Food

4

Golfscript(60)

自从obl。golfscript不见了,作为菜鸟,我还是需要练习:)

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

它只是用4个必需+ 11个随机字符构建一个数组,并以随机顺序排序。


为+1 {r}$。这是一种随机整理列表的肮脏方式-我喜欢!;-)
Ilmari Karonen 2014年

...但是,我认为这永远不会输出,例如0Aa~~~~~~~~~~~~。:-(
Ilmari Karonen 2014年

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 2014年

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

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 2014年

您是shuffle()“自定义功能” 是什么意思。它是JavaScript还是代码的一部分,您必须自己编写?
Hand-E-Food

@ Hand-E-Food我的意思是它不是内置在JavaScript中的,并且由于这里的任何开发人员都应该知道如何对数组进行混洗,所以我觉得没有必要在代码中包含该函数。不过,可以在JS小提琴(第16行)中找到它。
IQAndreas 2014年

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

在Action--2中查看


1
我在执行最后一行时遇到麻烦,但是代码似乎无法满足所有排列要求。
IQAndreas 2014年

您的代码将永远不会生成任何以开头的密码~0Aa,也不会生成任何b后跟的密码a
Heinzi 2014年

@Heinzi:是的,我同意所有需要的排列,而不考虑它仅显示15个长度。.字符从a ... z,A..Z,0..9,!... + :(中随机选择。 ..
vhadalgi 2014年

2

SAS(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)(?=.*[!#$%&? "]).*$,您可以与此进行一次匹配,仅当存在Upper,Lower,Digit,Symbol时才匹配。
Vasili Syrakis 2014年

@VasiliSyrakis好吧,您可能需要引导我一点。如果您认为需要一段时间,请随时启动聊天室。我感到困惑的几件事:1.)我看到其中包括15。这是为了确保字符串恰好是15个字符?如果是这样,可以将其省略,因为脚本自然生成15个字符的字符串。2.)您的意思是“只有在上,下,数字,符号只有一个时才匹配”?这是否意味着只有在每个正好有一个或至少一个时才匹配?前者会破坏事情。
Iszi 2014年

另外,您的RegEx是否忽略字符的顺序?例如,如果调低以匹配4个字符的字符串,则1aZ%和都(p3R匹配吗?我在网上找到方法遇到了一些困难。
Iszi 2014年

针对我当前脚本的输出测试了新的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
Iszi

如何打开聊天室?
Vasili Syrakis 2014年

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)。)
Ilmari Karonen 2014年


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 2014年

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

半脱胶

// 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//s 都不是很满意,但是似乎可以工作并且应该满足最终生成的条件所有排列。

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'

编辑以修正验证并在MvG注释后更改[[:punct:]][\W_]


1
您的生成部分很好,但是您在循环条件中的选择标准是完全错误的:例如,密码为aaaaaaaaaaaaaa会导致循环终止。您应该使用非随机密码测试条件,以确保它们按照您的要求进行操作。
MvG 2014年

确实,您是对的,我已解决此问题并节省了一些字节!谢谢!
Dom Hastings 2014年

1
您确定[[:punct:]]吗?我想我更喜欢'[\ W_] , which is shorter and of which I'm even more sure that it is correct, at least combined with your 33..127`范围。
MvG 2014年

很好的一点是,我想我担心其中\W不包含_,但是您绝对正确,不需要它:gist.github.com/anonymous/8301237。谢谢!
Dom Hastings

1

Java 7的(270 234个字符)

前提与@assylias在Java 8中使用的前提相同(生成随机密码直到有效密码)。但是,不是使用lambda,而是通过迭代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

电源外壳


一个Liner版本(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
}

感谢Iszi提供各种缩短代码的技巧。


1
这并不涵盖所有排列。作为一个例子,abcd1234ABCD{|}~永远也不会到来,因为$symbol符号的力量至少一个ASCII 33和47之间是
手工E-食品

该死的!您是否必须指出我的懒惰!?开个玩笑...我已经编辑了。我还使每个“要求”字符都转到了字符串中的单独索引,而不是将四个字符合并到同一索引中。现在,只要我能缩短这个时间...
Vasili Syrakis 2014年

您是否有任何理由不能缩短$SR至几个剃须刀$Q
Iszi 2014年

您还应该能够使用别名(g(65..90))65..90|g'. And change the 诸如toeach`语句之类的内容削减为foreach-object循环%。示例:foreach($N in (1..11)){... }应该像1..11|%{...一样可行}。我很确定还有其他可能的优化方法,但是我实际上打算将一个完全不同的实现方案考虑在内,我打算稍后再尝试。
Iszi 2014年

不错的提示:)如果取出回车符并替换为分号,我会将其缩短为213个字节。
Vasili Syrakis 2014年

1

因子196个字符

与MvG和驼鹿算法相同。它不是最短的,但应满足问题中的所有(当前)条件:

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则可以用putStrLn3个以上的字节替换。这是一个更具可读性的版本:

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随机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字符,因此所有可能的组合都是可能的。然后使用正则表达式模式检查其是否包含每个条件中的至少一个。

如果是,则显示密码,否则显示“ redo”。

感谢Bart Kiers的正则表达式模式:https : //stackoverflow.com/questions/1559751/regex-to-make-sure-that-the-string-contains-at-least-one-lower-case-char-上


0

自动热键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]。随机导入。列表中的数字乘以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
“它必须能够生成所有允许的字符的所有排列。” 我不认为这样做是因为范围始终以相同的顺序应用...?
Joachim Isaksson 2014年

你说得对,谢谢。实际上,我没有注意到应该按随机顺序应用范围,应该将其改组,稍后我将对其进行编辑。
Pawelmhm 2014年

这实际上需要包含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)));
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.