Regex: Any letters, digit, and 0 up to 3 special chars - regex

It seems I'm stuck with a simple regex for a password check.
What I'd like:
8 up to 30 symbols (Total)
With any of these: [A-Za-z\d]
And 0 up to 3 of these: [ -/:-#[-`{-~À-ÿ] (Special list)
I took a look here and then I wrote something like:
(?=.{8,15}$)(?=.*[A-Za-z\d])(?!([ -\/:-#[-`{-~À-ÿ])\1{4}).*
But it doesn't work, one can put more than 3 of the special chars list.
Any tips?

After shuffling your regex around a bit, it works for the examples you provided (I think you made a mistake with the example "A#~` C:", it should not match as it has 6 special chars):
(?!.*(?:[ -\/:-#[-`{-~À-ÿ].*){4})^[A-Za-z\d -\/:-#[-`{-~À-ÿ]{8,30}$
It only needs one lookahead instead of two, because the length and character set check can be done without lookahead: ^[A-Za-z\d -/:-#[-`{-~À-ÿ]{8,30}$
I changed the negative lookahead a bit to be correct. Your mistake was to only check for consecutive special chars, and you inserted the wildcards .* in a way that made the lookahead never hit (because the wildcard allowed everything).

Will this work?
string characters = " -/:-#[-`{-~À-ÿ";
string letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
string[] inputs = {
"AABBCCDD",
"aaaaaaaa",
"11111111",
"a1a1a1a1",
"AA####AA",
"A1C EKFE",
"AADE F"
};
foreach (string input in inputs)
{
var counts = input.Cast<char>().Select(x => new { ch = characters.Contains(x.ToString()) ? 1 : 0, letter = letters.Contains(x.ToString()) ? 1 : 0, notmatch = (characters + letters).Contains(x) ? 0 : 1}).ToArray();
Boolean isMatch = (input.Length >= 8) && (input.Length <= 30) && (counts.Sum(x => x.notmatch) == 0) && (counts.Sum(x => x.ch) <= 3);
Console.WriteLine("Input : '{0}', Matches : '{1}'", input, isMatch ? "Match" : "No Match");
}
Console.ReadLine();

I would use: (if you want to stick to Regex)
var specialChars = #" -\/:-#[-`{-~À-ÿ";
var regularChars = #"A-Za-z\d";
if (Regex.Match(password,$"^(.[{regularChars}{specialChars}]{7,29})$").Success && Regex.Matches(password, $"[{specialChars}]").Count<=3))
{
//Password OK
}
If consists of:
Check Length and if password contains illegal characters
Check if ony contains 3 times special char
A litle faster:
var specialChars = #" -\/:-#[-`{-~À-ÿ";
var regularChars = #"A-Za-z\d";
var minChars = 8;
var maxChars = 30;
if (password.Length >= minChars && password.Length <= maxChars && Regex.Match(password,$"^[{regularChars}{specialChars}]+$").Success && Regex.Matches(password, $"[{specialChars}]").Count<=3))
{
//Password OK
}

Newbie here..I think I've managed to get what you need but one of the test cases you shared was kinda weird..
A#~` C:
OK -- Match (3 specials, it's okay)
Shouldn't this be failed because it has more than 3 specials?
Could you perhaps try this? If it works I'll type out the explanations for the regex.
https://regex101.com/r/KCL6R1/2
(?=^[A-Za-z\d -\/:-#[-`{-~À-ÿ]{8,30}$)^(?:[A-Za-z\d]*[ -\/:-#[-`{-~À-ÿ]){0,3}[A-Za-z\d]*$

Related

The first digit matches the last digit in a four-digits number

I'm trying to find numbers that start and end with the same digit and have similar numbers in between the two digits. Here are some examples:
7007 1551 3993 5115 9889
I tried the following regular expression to identify the first and the last digit. However, no number was selected.
^(\d{1})\1$
I appreciate your help.
Use this:
(\d)(\d)\2+\1
Capture the first and second digits separately, then match them in the reverse order.
Demo
Maybe,
^(\d)(\d)\2+\1$
might be an option to look into.
RegEx Demo
If you wish to simplify/update/explore the expression, it's been explained on the top right panel of regex101.com. You can watch the matching steps or modify them in this debugger link, if you'd be interested. The debugger demonstrates that how a RegEx engine might step by step consume some sample input strings and would perform the matching process.
Your regex will match two digit numbers where both digits are the same. You just need to expand it: (\d)(\d)\2\1
As well, since the numbers are on the same line, use word boundaries (\b) instead of line boundaries (^ and $).
\b(\d)(\d)\2\1\b
BTW {1} is redundant
Demo on regex101
Simple JS way.
let a = "7007 1551 3393 5115 9883";
a = a.split(" ");
let ans = [];
a.forEach((val) => {
let temp = val.split("");
if (temp && temp[0] === temp[temp.length - 1]) {
temp = temp.slice(1,temp.length-1);
ans.push(temp.slice(0,temp.length).every( (val, i, arr) => val === arr[0] )) ;
} else {
ans.push(false);
}
});
console.log(ans);
Regular Expression:
let a = "7007 1551 3393 5115 9883";
a = a.split(" ");
let ans = [];
a.forEach((val) => {
let reg = /(\d)(\d*)(\d)/gi;
let match = reg.exec(val);
if (match && match.length > 3 && match[1] === match[3]) {
let temp = match[2];
temp = temp.split("");
temp = temp.slice(0,temp.length);
ans.push(temp.every( (val, i, arr) => val === arr[0] )) ;
} else {
ans.push(false);
}
});
console.log(ans);

Remove first zero values from string using regex

I've created a string value using padStart method (padLeft), for example:
"5".padStart(19, "0")
which results into "0000000000000000005"
How can I get that 5 back using regex?
I've tested this:
/^0*(\d+)$/.exec(d)[1]
which return 5 correctly.
But this regex returns null for something like "00000012.22"
Samples:
5 > 5
005 > 5
0011.22 > 11.22 >> This is a first problem!
00100 >> 100
001001 >> 1001
00.5 >> 0.5 This is a second problem!
Working codes but without regex:
function toDb(d) {
if (d == null) return null;
var precisionIndex = d.indexOf('.');
return d.toString().padStart((29 + precisionIndex + 1), '0');
}
function fromDb(d) {
if (d == null) return null;
d = d.replace(/^0+/, ''); // I'd like to use regex here
if (d.indexOf('.') == 0) // I'd like to use regex here
d = '0' + d; // I'd like to use regex here
return d;
}
fromDb(toDb('0.5')) returns 0.5 for me. But I'd like to use regex in my codes.
Use String#replace method to replace leading 0.
console.log(
"0000000000000000005".replace(/^0+(?=\d)/, '')
)
console.log(
"000000000000000000.5".replace(/^0+(?=\d)/, '')
)
In the regex start anchor(^) assert the beginning position of the string and 0+ matches combination one or more repetition of 0, altogether ^0+ matches 0s at the beginning.
UPDATE : To avoid removing 0 just before the . use positive look ahead assertion, (?=\d) match up to the 0 which follows a digit.

how to write regular expression to see if at least some statements in expression passed

I am new to regular expressions and was wondering how to write a regular expression that would pass if some of the statements in the expression pass.
For example I have this regex
^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*(_|[^\w])).+$
which matches if the string has
1 lowercase character,
1 uppercase character,
1 digit,
1 symbol.
Is it possible to have a regular expression that would pass if at least 3 of the 4 conditions were true in any order?
(i.e. would pass if string had 1 lower, 1 upper, 1 symbol, or 1 upper, 1 digit, 1 symbol, etc.)
Any help is appreciated!
The best approach I can propose you is to capture every type of characters in a capture group and make sure that at least 3/4 capture groups have a value (if the group can't match anything, it should be an empty string).
^(?:([a-z])|([A-Z])|(\d)|(_|[^\w]))+$
You can also add a positive lookahead to make sure that the password have the required length (by example 8 to 32 characters).
^(?=.{8,32}$)(?:([a-z])|([A-Z])|(\d)|(_|[^\w]))+$
Edit: ([\W_]) is the equivalent of (_|[^\w]). Putting the "W" in upper case reverse it sense (match all the non-word characters). Moreover, using a single character class is faster than alternation (more details here)
If you are willing to use javascript, I adapted a function presented in "Regular Expression cookbook second edition" for the needs of my website:
var PASSWORD_RANKING = {
TOO_SHORT: 0,
WEAK: 1,
MEDIUM: 2,
STRONG: 3,
VERY_STRONG: 4
};
/**
* Take a password and returns it's ranking
* based of the strength of the password (length, numeric character, alphabetic character, special character, etc.)
*
* #param password String
* #param minLength Int
*
* #return Int
*/
function rankPassword(password, minLength){
var rank = PASSWORD_RANKING.TOO_SHORT;
var score = 0;
if (typeof minLength !== 'number' || minLength < 6){
minLength = 8;
}
if (typeof password === 'string' && password.length >= minLength){
if (/[A-Z]/.test(password)){ score++;}
if (/[a-z]/.test(password)){ score++;}
if (/[0-9]/.test(password)){ score++;}
if (/[_~!#.#$%^&]/.test(password)){ score++;}
score += Math.floor((password.length - minLength) / 2);
if (score < 3){
rank = PASSWORD_RANKING.WEAK;
}
else if (score < 4){
rank = PASSWORD_RANKING.MEDIUM;
}
else if (score < 6){
rank = PASSWORD_RANKING.STRONG;
}
else {
rank = PASSWORD_RANKING.VERY_STRONG;
}
}
return rank;
}
The section 4.19 present many regexes to enforce password strength. You can see all the code samples online :
http://examples.oreilly.com/0636920023630/Regex_Cookbook_2_Code_Samples.html

Looking for a regex for a password with at least one lowercase letter, at least one upper case letter, at least one digit & length between 6 and 14

I am looking for a regular expression for a validating a password. The password rules are:
at least one lowercase letter
at least one upper case letter
at least one digit
length between 6 and 14
I created following regular expression but it's not working
^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{6,14}$
It's accepting
qwerty1
QWERTY1
but not qwERTy
i.e. it's fulfilling only 2 conditions
at least one digit
length between 6 and 14
I'm not sure that's possible, but I'm sure that if it is, and it turns out a long complicated regex string, it's a wrong design decision. It will be unmaintainable, unclear and very error prone.
At the same time, this is easy to do, understand and maintain:
function isValid(password)
{
if(password.length < 6 || password.length > 14)
return false;
var valid = { hasLower: false, hasUpper: false, hasDigit: false };
for(var i = 0; i < password.length; i++) {
var c = password[i];
var upperC = c.toUpperCase();
valid.hasLower |= c != upperC;
valid.hasUpper |= c == upperC;
valid.hasDigit |= c >= '0' && c <= '9';
}
return valid.hasLower && valid.hasUpper && valid.hasDigit;
}
alert('"123abcDEF" valid = ' + isValid('123abcDEF'));
alert('"123 DEF" valid = ' + isValid('123 DEF'));
You can use \S instead of . for restricting spaces:
^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])\S{6,14}$
^
See DEMO

How do I count odd and even amounts of characters with regular expressions?

I'm trying to pull out all strings which have an even number of B's and an odd number of C's. I have the regexes to match odd A's and even B's but I cannot get the two to work together. The strings are delimited by whitespace (tabs, newlines, spaces).
e.g.
XABBAC ABCDEBCC ABSDERERES ABBAAJSER HGABAA
I have for odd A's
\b[^A]*A([^A]*A[^A]*A)*[^A]*\b
And for even B's
\b[^B]*(B[^B]*B[^B]*)*[^B]*\b
I know I need to use +ve lookahead and have tried:
\b(?=[^A]*A([^A]*A[^A]*A)*[^A]*\b)[^B]*(B[^B]*B[^B]*)*[^B]*\b
but it doesn't work - does anybody know why?
The problem is that your regexes (regexen?) can match zero characters - \b\b will match on a single word boundary, and so will \b{someregexthatcanmatchzerocharacters}\b.
As Anon already mentioned: your pattern matches empty strings, causing m.find() to never advance in the target string. So, you need to let your even B's actually match Strings containing 2, 4, 6, ... number of B's. If you want, you can alternate between an even number of B's and this: [^B\\s]+ (which matches Strings containing 0 B's). As long as you actually match one or more character with it, then you should be okay.
Also, you don't want to look ahead and let the negated classes match spaces: that way you get too much matches.
Try something like this:
String text = "XABBAC ABCDEBCC ABSDERERES ABBAAJSER HGABAA";
String oddAs = "\\b[^A\\s]*A([^A\\s]*A[^A\\s]*A)*[^A\\s]*\\b";
String evenBs = "\\b([^B\\s]*(B[^B\\s]*B[^B\\s]*)+|[^B\\s]+)\\b";
Pattern p = Pattern.compile(String.format("(?=%s)(?=%s)\\S+", oddAs, evenBs));
Matcher m = p.matcher(text);
while (m.find()) {
System.out.println(m.group());
}
which produces:
ABCDEBCC
ABBAAJSER
With commons.lang.StringUtils it's even more concise:
String data = "XABBAC ABCDEBCC ABSDERERES ABBAAJSER HGABAA";
String[] items = data.split("\\s+");
for(String item: items ) {
if (countMatches(item, "B") % 2 == 0
&& countMatches(item, "C") % 2 != 0) {
System.out.println( item );
}
}
regex is overrated
String str = "XABBAC ABCDEBCC ABSDERERES ABBAAJSER HGABAA";
String[] s = str.split("\\s+");
for (int j=0 ;j< s.length;j++) {
int countC=0 ;
int countB=0;
for(int i=0;i<s[j].length();i++){
char c = s[j].charAt(i) ;
if (c == 'C') countC++;
if (c == 'B') countB++;
}
if ( (countC % 2) != 0 )
System.out.println( s[j] + " has odd C");
if ( (countB % 2) == 0 )
System.out.println( s[j] + " has even B");
}