开发者

Use JS regexp to check if certain chars are in string

I am working on a JS function for generating password strings, it takes four parameters for a-z lowercase, A-Z uppercase, 0-9 and punctuations. I put together a base string, like this:

function genpwd(azlc,azuc,num,pun,len) {
    var chars = "";
    if (azlc) chars += "abcd开发者_Python百科efghijklmnopqrstuvwxyz";
    if (azuc) chars += "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    if (num)  chars += "012345678901234567890123";
    if (pun)  chars += "!@#%&()=?+-_.:,;*{}[]^$/";

Then I loop through the base string (given length of the password) and randomly picking out chars to a new string and returns this as the output password.

    for(i=0;i<len;i++) {
        nextChar = chars.charAt(Math.floor(Math.random()*charsN));
        password += nextChar;
    }
    return password;
}

This is a really simple way of generating a random string, but it does not guarantee that at least one char from each "char group" actually is included in the output string.

I have looked at some other examples on how to use regexps, but can't figure out how to modify them to work the way I want. I'm thinking the "easiest" way to solve this is probably by using a regexp - something like this:

if (password.magic_regexp_stuff) {
    return password;
} else {
    password = genpwd(azlc,azuc,num,pun,len);
}
  1. Am I on the right track?
  2. Can anyone help me with the regexp?

UPDATE:

Ok, so after some valuable input from all of you, I ended up with this function.

I also switched from mVChr suggestion (thanks man!) to the one posted by Py, so I'm pretty sure the "statistics problem" (don't have any other word for it) pointed out by NobRuked won't be a problem any more. Can someone confirm this please? :)

I also had to modify the function's parameters and approach to the sets of chars to be used. Any suggestions on improvements?

function passwd(len, azlc, azuc, num, pun) {
    var len = parseInt(len),
        ar = [],
        checker = [],
        passwd = '',
        good = true,
        num, num2,
        sets = 0;
    if(!len || len < 4) len = 12;
    if(!azlc && !azuc && !num && !pun) { azlc = 1; azuc = 1; num = 1; pun = 1; }    

    if (azlc) {
        ar.push("abcdefghijklmnopqrstuvwxyz");
        checker.push(0);
        sets++;
    }
    if (azuc) {
        ar.push("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
        checker.push(0);
        sets++;
    }
    if (num) {
        ar.push("0123456789");
        checker.push(0);
        sets++;
    }
    if (pun) {
        ar.push("!@#%&()=?+-_.:,;*{}[]^$/");
        checker.push(0);
        sets++;
    }
    for (var i=0;i<len;i++){
        num=rand(0,sets);
        num2=rand(0,ar[num].length);
        passwd+=ar[num][num2];
        checker[num]=1;
    }
    for (var i=0;i<sets;i++){
        if(checker[i]===0)
            good=false;
    }
    if (good){
        return passwd;
    }
    else{
        return passwd(len);
    }
}

Many thanks to everyone for your help, it's appreciated!


I don't think regular expressions are the right tool for the job. Your attempt could theoretically loop forever (though highly unlikely) since there is no guarantee a generated password will ever match the regular expression.

I guess the easy way of making sure one character from each group is included is to explicitly include it. So, assuming your password is to be at least 4 characters long, I would suggest the following pseudo-code:

chars = charFrom(azlc) + charFrom(azuc) + charFrom(num) + charFrom(pun)
do the following, length_of_password - 4 times:
    chars += charFrom(azlc + azuc + num + pun)
chars = shuffle(chars)

Implementation of charFrom() and shuffle() are left as an exercise to the reader.


To do this with regular expressions, you really just need (up to) four regular expressions:

function genpwd(azlc,azuc,num,pun,len) {
    var chars = "", regexs = [],

    testRegexs = function(pw) {
        var ii;
        for (ii = 0; ii < regexs.length; ii += 1) {
            if (!regexs[ii].test(pw)) {
                return false;
            }
            return true;
        }
    };

    if (azlc) { 
        chars += "abcdefghijklmnopqrstuvwxyz"; 
        regexs.push(/[a-z]/); 
    }
    if (azuc) { 
        chars += "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 
        regexs.push(/[A-Z]/); 
    }
    if (num) { 
        chars += "012345678901234567890123"; 
        regexs.push(/0-9/); 
    }
    if (pun) { 
        chars += "!@#%&()=?+-_.:,;*{}[]^$/"; 
        regexs.push(/[\!\@\#\%\&\(\)\=\?\+\-\_\.\:\,\;\*\{\}\[\]\^\$\/]/); 
    }

    do
    {
        // Generate a password...
    }
    while (!testRegexs(password));

    return password;
}


I would take another approch.

I'd have 4 strings

lower = "abcdefghijklmnopqrstuvwxyz";
upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
num = "0123456789";
other = "!@#%&()=?+-_.:,;*{}[]^$/";

Then to generate the password, i'll take a random integer between 0 and 3, and then another integer between 0 and the choosen string to take a character.

To check if everything was taken, I'd just have to check that the 4 integer have been taken in the first random choice.

the code would look like

function psswd(len){
    var ar=[lower,upper,num,other],
        checker=[0,0,0,0],
        passwd="",
        good=true,
        num,num2;
    for (var i=0;i<len;i++){
        num=randomInt(0,3);
        num2=randomInt(0,ar[num].length);
        passwd+=ar[num][num2];
        checker[num]=1;
    }
    for (var i=0;i<3;i++){
        if(checker[i]===0)
            good=false;
    }
    if (good){
        return passwd;
    }
    else{
        return psswd(len);
    }
}

Might not be optimal, but no regexp needed.


function genpwd(azlc,azuc,num,pun,len) {
  var sets = [], 
      pw = [],
      i, j, t;
  if (azlc) sets.push("abcdefghijklmnopqrstuvwxyz");
  if (azuc) sets.push("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
  if (num)  sets.push("0123456789");
  if (pun)  sets.push("!@#%&()=?+-_.:,;*{}[]^$/");
  while (len) {
   pw.push(sets[len%sets.length][~~(Math.random()*sets[len%sets.length].length)]);
   len--;
  }
  i = pw.length;
  while (--i) {
    j = ~~(Math.random()*(i+1));
    t = pw[j];
    pw[j] = pw[i];
    pw[i] = t;
  }
  return pw.join('');
}

EDIT: added shuffle


Just for the record, validation can be done in a single regex:

/^(?=.*[A-Z])(?=.*[a-z])(?=.*\d)(?=.*[!@#%&()=?+_.:,;*{}\[\]^$\/-])/.test(mypassword)

As for your password generation scheme, see this.


This is the final version of my function (I also updated the question post with some info).

Thanks again to everyone helping me! :)

/**
 * Generate Password
 * ---
 * Generates a random text string containing characters types according to given 
 * parameters. Uses all character types by default. Output string length will at 
 * minimum be the number of character types currently in use.
 *
 * @param   int     Output string lenght
 * @param   bool    Use letters a-z lower case
 * @param   bool    Use letters A-Z upper case
 * @param   bool    Use numbers 0-9
 * @param   bool    Use punctuations (!@#$?*...)
 * @return  string  Generated password string
 */

function genPwd(l,w,x,y,z){
    var a=[],c=[],p='',g=true,n1,n2,s=0,i=0;
    if(!w&&!x&&!y&&!z){w=1,x=1,y=1,z=1;}
    if(w){c.push(0);s++;a.push("abcdefghijklmnopqrstuvwxyz");}
    if(x){c.push(0);s++;a.push("ABCDEFGHIJKLMNOPQRSTUVWXYZ");}
    if(y){c.push(0);s++;a.push("012345678901234567890123456789");}
    if(z){c.push(0);s++;a.push("!@#%&/(){}[]=?+*^~-_.:,;");}
    if(l<s){l=s;}for(i=0;i<l;i++){n1=Math.floor(Math.random()*(s-0));
    n2=Math.floor(Math.random()*(a[n1].length-0));p+=a[n1][n2];c[n1]=1;}
    for(i=0;i<s;i++){if(c[i]===0)g=false;}
    if(g){return p;}else{return genPwd(l,w,x,y,z);}
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜