2
$\begingroup$

I legitimately think the problem is that pwgenerator isn't getting defined, but im' not sure why. Any ideas? On mine, when i run this to define it, pwgenerator stays blue for some reason, and it didn't before.

  pwgen[length_Integer:5, num_Integer:1, similars_Boolean:1] := 
 pwgenerator[length, num, similars] = 
  Module[{list, valid, validchars, similar, k, j, password, pwlist, 
    lcase, ucase, digits, spec, s}, lcase = Alphabet[];
   ucase = Capitalize[lcase];
   digits = Range[0, 9];
   spec = StringPartition["!:#$%\'()*+,-./:;>=<?@{}[]^_|~", 1];
   validchars = Flatten[Union[lcase, ucase, digits, spec]];
   similar = StringPartition["Il10O5S2Z", 1];
   list = {};
   (* Evleything above here sets up valid keys to use for password generation *)
   Table[valid = 0;
    While[valid == 0,
     For[j = 0; k = {};, j < length, j++, 
      AppendTo[k, RandomInteger[{1, Length[validchars]}]]]; (* FOR creates 
random integer values between 1 and Length[validchars] *)
     k = Flatten[k];
     password = validchars[[k]]; (* take those elements out, and check if 
there are any of the similar in the password.*)
(* If there is, and similars is 0, restart and reselect the password. If 
there isn't, and similars is 1, we do the same, otherwise we accept the 
password and Return it *)
     Which[(Length[Intersection[password, similar]] >= 1 && similars == 0 ), 
      valid = 0;, (Length[Intersection[password, similar]] == 0 && 
        similars == 1), 
      valid = 0;, (Length[Intersection[password, similar]] == 0 && 
        similars == 0 ), valid = 1; 
      Return[password], (Length[Intersection[password, similar]] >= 1 && 
        similars == 1), valid = 1; Return[password]];
     ], {num}];


   ]
$\endgroup$
4
  • $\begingroup$ It's hard to debug if I don't know what everything is supposed to be doing. When I run this, it just runs and doesn't return anything, how long should it take? You have a While loop there, how often do you expect it to run before returning? Can you put in Print or Echo statements to see if they are changing as you expect them to? $\endgroup$
    – Jason B.
    Apr 28, 2018 at 1:47
  • 1
    $\begingroup$ But I do see code like this, Intersection[password, similar] >= 1 that is problematic, since Intersection is going to return a list, which isn't comparable to an integer. I think you want to use Length there $\endgroup$
    – Jason B.
    Apr 28, 2018 at 1:49
  • $\begingroup$ @JasonB. Yes you are right about that. I’ll add details and comments momentarily so everything is clearer $\endgroup$
    – Shinaolord
    Apr 28, 2018 at 2:05
  • $\begingroup$ Do the comments i added help @JasonB? It should only take a couple seconds to run. Mine just spits back out what i input; ie pwgen[5,1,1] outputs pwgen[5,1,1]. I $\endgroup$
    – Shinaolord
    Apr 28, 2018 at 3:13

1 Answer 1

2
$\begingroup$

I think the following has the same functionality:

ClearAll[pwgen];
pwgen[length_Integer: 5, num_Integer: 1, similarsallowedQ_: True] := 
 pwgenerator[length, num, similarsallowedQ] = 
  Module[{notvalid, validchars, similar, password},
   validchars = Union[
     Alphabet[],
     Capitalize[Alphabet[]],
     IntegerString[Range[0, 9]],
     StringPartition["!:#$%\'()*+,-./:;>=<?@{}[]^_|~", 1]
     ];
   If[Not[similarsallowedQ],
    validchars = Complement[validchars, StringPartition["Il10O5S2Z", 1]];
    ];
   RandomChoice[validchars, {num, length}]
   ]

There were numerous issues with your original code:

There is no built-in head Boolean in Mathematica.

Instead of doing AppendTo[k, RandomInteger[{1, Length[validchars]}]]] in a For loop, you can just do RandomInteger[{1, Length[validchars]}, length]. Append has to copy the whole list, so it makes the code needlessly slow to execute.

Instead of password = validchars[[k]]; you can have password = RandomChoice[validchars, length] right from the beginning.

Instead of first generating passwords and throwing out the invalid ones, you can attempt to generate valid passwords at the first place by setting validchars = Complement[validchars,similar]. That saves you the whole While loop. However, I admit that this may be not so easy for more complicated rules for validity.

Using Return is almost always wrong in Mathematica. Moreover, you compute the same intersections multiple times. Your Table could look like this.

Table[
  notvalid = True;
  While[notvalid,
   password = RandomChoice[validchars, length];
   n = Length[Intersection[password, similar]];
   Which[
    (n >= 1 && ! similarsallowed), notvalid = True,
    (n == 0 && similarsallowed), notvalid = True,
    (n == 0 && ! similarsallowed), notvalid = False,
    (n >= 1 && similarsallowed), notvalid = False
    ];
   ];
  password,
  {num}
  ];

Moreover, my understanding is that if similars are allow but a generated password contains no similars then it should still be valid, but that is your decision.

$\endgroup$
1
  • 1
    $\begingroup$ It was more just to see if I could get a function working that had optional arguments, not actually making a legitimate password generator. I also like the way you made it much more concise. Thanks. The reason mine wasn’t defining was due to the Boolean head. $\endgroup$
    – Shinaolord
    Apr 28, 2018 at 16:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.