0

Sorry for repeating the question of others. I have looked at those answers but still struggling to accomplish what i need.

I want to keep trying my password generator function until it gives me one which has a symbol, a number and a upper case letter in it.

Can you help?

while (true) {
  let trialPassword = randomPassGen(10)

  trialPassword.forEach((letter)=>{
    if (!upperLetters.includes(letter)){
      return
    } else if (!symbols.includes(letter)) {
      return
    } else if (!numbers.includes(letter)) {
      return
    } else {
      break
    }
  })
  console.log(trialPassword)
}

EDIT: here's the full code for my password generator. Trying this time with a for loop but still no luck. Thanks all!

const upperLetters = [
  'A','B','C','D','E','F','G','H','I','J','K','L','M','N','P','Q','R','S','T','U','V','W','X','Y','Z'
]

const lowerLetters = []

// build lowerLetters from upper skipping lowecase L which could be seen as a 1
upperLetters.forEach((letter)=>{
  if(letter !== 'L'){
    lowerLetters.push(letter.toLowerCase())
  }
})
// skips letter l

const numbers = [0,1,2,3,4,5,6,7,8,9]

const symbols = [
  '!', '@', ';', ':', '$', '£', '#', '[', ']', '?', '<', '>'
]

const allChars = []

symbols.forEach((sym)=>{
  allChars.push(sym)
})

numbers.forEach((num)=>{
  allChars.push(num)
})

lowerLetters.forEach((lowLet)=>{
  allChars.push(lowLet)
})

upperLetters.forEach((upLet)=>{
  allChars.push(upLet)
})

const randomPassGen = (passLength) => {
  passArr = []

  for (let i = 0; i <= passLength; i++) {
    let r = Math.floor(Math.random() * allChars.length);
    passArr.push(allChars[r])
  }
    return passArr
  }



while (true) {
  let trialPassword = randomPassGen(chosenLength)

  for (let i = 0; i <=trialPassword.length; i++){
    let l = trialPassword[i]
    if(!upperLetters.includes(l)){
      continue
    } else if (!symbols.includes(l)){
      continue
    } else if (!numbers.includes(l)){
      continue
    } else {
      console.log(trialPassword)
      break
    }
  }
}
CAF
  • 13
  • 3
  • 3
    `break` cannot be used inside a `forEach`, from MDN documentation: *"There is no way to stop or break a forEach() loop other than by throwing an exception. If you need such behavior, the forEach() method is the wrong tool."* – Calvin Nunes Nov 18 '19 at 20:53
  • 2
    Why not change the `randomPassGen` to generate a password which has at least one symbol, number and an upper case letter? – adiga Nov 18 '19 at 20:53
  • I see you are trying to return something. Is this in a function? If so, can you post all of the code? – Jonathan Irvin Nov 18 '19 at 20:54
  • 1
    Try using a for-of instead of a for-each. Also, if you're trying to `break` out of the `while (true)` loop, then you'll need a second break, since the first will just leave the `for`. Use a boolean on `for`-break to check if the `while` loop should break as well. – matthew-e-brown Nov 18 '19 at 20:55

3 Answers3

1

If your intention is to get out of the while loop, use a variable as a flag, and set the flag in your forEach loop:

var keepgoing=true;
while (keepgoing) {
  let trialPassword = randomPassGen(10)

  trialPassword.forEach((letter)=>{
    if (!upperLetters.includes(letter)){
      keepgoing=false; return;
    } else if (!symbols.includes(letter)) {
      keepgoing=false; return;
    } else if (!numbers.includes(letter)) {
      keepgoing=false; return;
    } else {
      keepgoing=false;
    }
  })
  console.log(trialPassword)
}

Also, the if/else if chain is bad coding style, but that's another topic.

Ian Heisler
  • 111
  • 6
  • Thanks. I liked this one but it goes round on an infinite loop for me... – CAF Nov 18 '19 at 21:02
  • Change your "returns" to "keepgoing=false; return"; – Ian Heisler Nov 18 '19 at 21:02
  • I have upvoted your answer to counter the downvote. Your question is very legit and I think answering it gives you a learning opportunity, which is in line with the spirit of this website. – Ian Heisler Nov 18 '19 at 21:08
  • Thanks. I like this proffered answer as it retains my original coding plan but it now doesn't seem to go around the loop until it finds a password with all required characters. It just gives me the first one. – CAF Nov 19 '19 at 08:40
0

Break doesn't work inside forEach. Without throwing an exception, you won't be able to stop forEach.

Edit:

Tried to optimize your code. You can run this and generate password.

const upperLetters = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'];

const lowerLetters = [];

// build lowerLetters from upper skipping lowecase L which could be seen as a 1
upperLetters.forEach((letter) => {
    if (letter !== 'L') {
        lowerLetters.push(letter.toLowerCase())
    }
})
// skips letter l

const numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];

const symbols = ['!', '@', ';', ':', '$', '£', '#', '[', ']', '?', '<', '>']

const allChars = []

symbols.forEach((sym) => {
    allChars.push(sym)
})

numbers.forEach((num) => {
    allChars.push(num)
})

lowerLetters.forEach((lowLet) => {
    allChars.push(lowLet)
})

upperLetters.forEach((upLet) => {
    allChars.push(upLet)
})

const randomPassGen = (passLength) => {
    let passArr = [];
    for (let i = 0; i <= passLength; i++) {
        let r = Math.floor(Math.random() * allChars.length);
        passArr.push(allChars[r])
    }
    return passArr.join('');
};


function getPassword() {

    let regex = /[A-Z]+|[0-9]+|[!@;:$£#[\]?<>]+/g
    let str = randomPassGen(10);

    let hasNumber = false;
    let hasUpperCase = false;
    let hasSpecial = false;
    let match = null;

    do {
        match = regex.exec(str);
        if (match) {
            if (hasSpecial && hasNumber && hasUpperCase)
                break;
            let char = match[0][0];
            if (char >= 'A' && char <= 'Z')
                hasUpperCase = true;
            else if (char >= '0' && char <= '9')
                hasNumber = true;
            else
                hasSpecial = true;
        }
    } while (match);

    if (hasSpecial && hasNumber && hasUpperCase)
        return str;
    return getPassword();
}

console.log(getPassword());
Roy
  • 1,189
  • 7
  • 13
  • He may be trying to break from the while loop. – Jonathan Irvin Nov 18 '19 at 20:55
  • Maybe, but as it's inside forEach, it won't work for while loop. – Roy Nov 18 '19 at 20:56
  • That is definitely true. – Jonathan Irvin Nov 18 '19 at 20:59
  • so if i change it to a for loop can break? – CAF Nov 18 '19 at 21:03
  • @CAF, Yes you can. – Roy Nov 18 '19 at 21:06
  • This solution of using Regex to run the check seems elegant. I can't get it to work in my environment though. I probably should have said this code is to be run within a Node backend rather than a browser. The error this solution gives me is str.matchAll is not a function – CAF Nov 19 '19 at 17:31
  • @CAF, I have updated the code so that it supports Node. – Roy Nov 19 '19 at 19:02
  • Thank you for this Roy. It's very tidy but is a little too far from my original pattern which deliberately avoided the fromCharCode option since it's harder to comment out certain characters (such as lower case L). The regex checker is certainly neat though... – CAF Nov 20 '19 at 20:03
  • @CAF, OK, I did put all yours previous loops. – Roy Nov 20 '19 at 20:20
0

I think your password needs to have at least three types of characters to be valid: numbers, symbols, & upper case letters.

const upperLetters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
const numbers = [1,2,3,4,5,6,7,8,9,0];
const symbols = '!@;:$£#[]?<>';                  
let num = false, sym = false, upperCase = false;
const allChars = [...upperLetters.split(''), ...upperLetters.toLowerCase().split(''), ...numbers, ...symbols];

const randomPassGen = (passLength) => {
  passArr = []

  for (let i = 0; i <= passLength; i++) {
    let r = Math.floor(Math.random() * allChars.length);
    passArr.push(allChars[r])
  }   
  return passArr
}

while (true) {
  let trialPassword = randomPassGen(10)

  trialPassword.forEach(letter => {
    if(upperLetters.includes(letter)){
      upperCase = true;
      return;
    }
    if(symbols.includes(letter)){
      sym = true;
      return;
    }
    if(numbers.includes(Number(letter))){
      num = true;
      return;
    }
  })

  if(num && sym && upperCase){
    console.log(trialPassword);
    break;
  }
}

Edit: you get an infinite loop because there is no exit condition for the infinite while loop. Exit the while loop when you get the first valid password. I have edited the answer to reflect this.

Addis
  • 2,480
  • 2
  • 13
  • 21
  • this solution doesn't include the randomPassGen function so to test it i had to combine it with my original code and comment out parts of yours. When i do that and run it i get an infinite loop of passwords it keeps trying. – CAF Nov 19 '19 at 17:38
  • @CAF, your original question didn't include the randomPassGen fn, so my assumption was you had this function working properly. I will see what's wrong with this fn now. – Addis Nov 19 '19 at 17:49
  • Thanks this works for me and is also closest to my code while being more elegant through use of things like the spread operator. – CAF Nov 20 '19 at 20:01