0

I am trying to get a random value from a list multiple times in JS. I get the value of the "length" input from user, and then get that many characters that many times from the list in javascript................

JS:

toUpper = function(x){ 
  return x.toUpperCase();
};
function gen() {
    var symbol = document.getElementById("symbolsCB");
    var number = document.getElementById("numbersCB");
    var upper = document.getElementById("uppersCB");
    var length = document.getElementById("numberOfChars");
    var op = document.getElementById("outputBox");
    var list = ["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z",];
    if (symbol.checked == true){
        var symbols = ["?","!","@","#","$","%","^","&","*","(",")",",",".","+","=","[","]","{","}",";",":","<",">"];
        symbols.push.apply(list, symbols);
        let char = list[Math.floor(Math.random() * list.length)];
        op.innerHTML = char;
    }
    if (number.checked == true){
        var numbers = ["1","2","3","4","5","6","7","8","9","0",];
        numbers.push.apply(list, numbers);
        let char = list[Math.floor(Math.random() * list.length)];
        op.innerHTML = char;
    }
    if (upper.checked == true){
        var upperslower = ["A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"];
        uppers = upperslower.map(toUpper);
        uppers.push.apply(list, uppers);
        let char = list[Math.floor(Math.random() * list.length)];
        op.innerHTML = char;
    }
}

HTML:

<div class="page">
  <title> Random Password Generator </title>
  <header>
    <h1> Random Password Generator </h1>
  </header>
  <br><br>
  <input type="checkbox" name="numbers" id="numbersCB" class="cb">
  <label for="numbers"> Inculde Numbers </label>
  <br><br>
  <input type="checkbox" name="uppers" id="uppersCB" class="cb">
  <label for="uppers"> Inculde Uppercase Letters </label>
  <br><br>
  <input type="checkbox" name="symbols" id="symbolsCB" class="cb">
  <label for="symbols"> Inculde Symbols ( e.g. @ # $ % ) </label>
  <br><br>
  <input type="text" id="numberOfChars" name="numberOfChars" placeholder="Length of password...">
  <br><br>
  <button onclick="gen()"> Generate Random Password </button>
  <br><br>
  <input type="text" id="outputBox" name="outputBoxName" disabled="disabled">
  <br>
</div>
  <script type = "text/javascript" src = "js.js"></script>
  • 2
    Can you try to explain some more what you mean? Are you trying to simplify your existing code or add something to it? What is the desired output and what do you currently get? – Stuart May 04 '20 at 22:47
  • @stuart I am trying to get desired number of characters... So if the user puts 10 in the input box, i need 10 random characters from list –  May 04 '20 at 22:49
  • With or without replacement? (so can the same number be randomly chosen twice?) – Garrett Motzner May 04 '20 at 22:50
  • Does this answer your question? [How to get n no elements randomly from an array](https://stackoverflow.com/questions/19269545/how-to-get-n-no-elements-randomly-from-an-array) – Stuart May 04 '20 at 22:52
  • @GarrettMotzner yes the same cannot be chosen twice –  May 04 '20 at 22:53
  • I will comment that `symbols.push.apply(list, symbols)` is the same as `list.push.apply(list, symbols)` is the same as `list.push(...symbols)`. Same goes for `numbers.push.apply(...)` and `uppers.push.apply(...)` – Mulan May 04 '20 at 22:59

2 Answers2

0

Your logic is not optimal: you want to first build the list of symbols, and then extract as many characters as required.

function gen() {
    var symbol = document.getElementById("symbolsCB");
    var number = document.getElementById("numbersCB");
    var upper = document.getElementById("uppersCB");
    var length = document.getElementById("numberOfChars");
    var op = document.getElementById("outputBox");
    op.innerHTML = '';
    // Add letters. These are always present.
    var list = ["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z",];
    if (upper.checked == true){
        list = list.concat(["A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"]);
    }
    // If the first letter of the password cannot be a number or a symbol,
    // add one character here and decrement length by 1.
    if (number.checked){
        list = list.concat(["1","2","3","4","5","6","7","8","9","0",]);
    }
    // If the first letter of the password cannot be a symbol,
    // add one character here and decrement length by 1.
    if (symbol.checked) {
        list = list.concat(["?","!","@","#","$","%","^","&","*","(",")",",",".","+","=","[","]","{","}",";",":","<",">"]);
    }
    // Now generate the password until the full length has been reached.
    // Duplicate symbols are allowed to increase security.
    while (op.innerHTML.length < length) {
        op.innerHTML += list[list.length * random()];
    }
}
LSerni
  • 55,617
  • 10
  • 65
  • 107
  • 1
    but we are sampling without replacement, so this doesn't work... – Garrett Motzner May 04 '20 at 23:17
  • @GarretMotzner I had not seen the comment. It is however possible to increase complexity, at the same time slightly reducing security, by using Array.splice() to extract a random character from the array (this is probably as good a point as any to refer to XKCD' s "horse battery staple correct" comic ) – LSerni May 04 '20 at 23:48
0

I would suggest breaking the problem down into smaller parts -

const lowers =
  "abcdefghijklmnopqrstuvwxyz"

const uppers =
  "ABCDEFGHIJKLMNOPQRSTUVWXYZ"

const numbers =
  "0123456789"

const symbols =
  "!@#$%^&*()_+"

const rand = (n = 0) =>
  Math.floor(Math.random() * n)

const makeRand = (...seeds) =>
{ const size =
    seeds.reduce((r, s) => r + s.length, 0)
  
  const generator = _ =>
  { let r = rand(size)
    for (const s of seeds)
      if (r >= s.length)
        r -= s.length
      else
        return s[r]
  }
  
  return n =>
    Array.from(Array(n), generator).join("")
}

const generator1 =
  makeRand(lowers, uppers)
  
const generator2 =
  makeRand(lowers, uppers, numbers, symbols)

console.log(generator1(10), generator1(20))
// LOTuXWBGOY    yUjvsEycrXIZTCyYePfq

console.log(generator2(10), generator2(20))
// jRE#f0Kji#    AHjiysQElD+UkDQY08m1
Mulan
  • 129,518
  • 31
  • 228
  • 259