Why does this simple JavaScript password regex not work? - javascript

I am building a password checker - I have a simple requirement for at least three lowercase non-consecutive letters for now and either I have a large misunderstanding of regexes, or something else.
I have written the following code:
var password = 'mYpAsSwOrD',
r = new RegExp('[a-z]{3,}', 'g');
console.log(password.match(r)); // null
console.log(r.test(password)); // false
Also, is the 'g' flag needed? Does the quantifier not provide the same functionality effectively?
What is the better comparison? Matching the regex against the string (first example); or testing the string against the regex (second example)?

It matches only the strings which has atleast 3 lowercase letters.
> /^(?:[^a-z]*[a-z]){3}/.test("mYpAsSwOrD")
true
Explanation:
^ Asserts that we are at the start.
(?..) Called non-capturing groups, which won't capture any characters but would do only matching operation.
[^a-z]* this would match any character zero or more times.
[a-z] this would match a lowercase letter.
(?:[^a-z]*[a-z]){3} So if the whole non-capturing group is repeated three times, it could match the strings with atleast three lowercase letters. For testing purposes only , we don't need to go for a full match.
OR
You could try the below positive lookahead.
^(?=(?:[^a-z]*[a-z]){3})
Code:
> /^(?=(?:[^a-z]*[a-z]){3})/.test("mYpAsSwOrD")
true

(?=(.*?[a-z]){3}).*
You can try this.See demo.
http://regex101.com/r/hQ1rP0/24

Your original regex matches where the three desired characters are consecutive. You can change the regex to this:
r = /[a-z](?:[^a-z]*[a-z]){2}/;
[a-z] Matches a lowercase character.
(?:[^a-z]*[a-z]) Skips over all non-lowercase characters and attempts to match a lowercase character.
{2} Two times.
As for your other question, the g flag is not necessary as it allows repeat matches, while for your use case you're simply matching the first collection and asserting true for return.

Related

Match the alphanumeric words(NOT NUMERIC-ONLY words) which have unique digits

Using regular expression, I want to select only the words which:
are alphanumeric
do not contain only numbers
do not contain only alphabets
have unique numbers(1 or more)
I am not really good with the regex but so far, I have tried [^\d\s]*(\d+)(?!.*\1) which takes me nowhere close to the desired output :(
Here are the input strings:
I would like abc123 to match but not 123.
ab12s should also match
Only number-words like 1234 should not match
Words containing same numbers like ab22s should not match
234 should not match
hel1lo2haha3hoho4
hel1lo2haha3hoho3
Expected Matches:
abc123
ab12s
hel1lo2haha3hoho4
You can use
\b(?=\d*[a-z])(?=[a-z]*\d)(?:[a-z]|(\d)(?!\w*\1))+\b
https://regex101.com/r/TimjdW/3
Anchor the start and end of the pattern at word boundaries with \b, then:
(?=\d*[a-z]) - Lookahead for an alphabetical character somewhere in the word
(?=[a-z]*\d) - Lookahead for a digit somewhere in the word
(?:[a-z]|(\d)(?!\w*\1))+ Repeatedly match either:
[a-z] - Any alphabetical character, or
(\d)(?!\w*\1) - A digit which does not occur again in the same word
Here is a bit shorter & faster regex to make it happen since it doesn't assert negative lookahead for each character:
/\b(?=[a-z]*\d)(?=\d*[a-z])(?!\w*(\d)\w*\1)[a-z\d]+\b/ig
RegEx Demo
RegEx Details:
\b: Word boundary
(?=[a-z]*\d): Make sure we have at least a digit
(?=\d*[a-z]): Make sure we have at least a letter
(?!\w*(\d)\w*\1): Make sure digits are not repeated anywhere in the word
[a-z\d]+: Match 1+ alphanumericals
\b: Word boundary
You could assert all the conditions using one negative lookahead:
\b(?![a-z]+\b|\d+\b|\w*(\d)\w*\1)[a-z\d]+\b
See live demo here
The important parts are starting match from \b and immediately looking for the conditions:
[a-z]+\b Only alphabetic
\d+\b Only numeric
\w*(\d)\w*\1 Has a repeating digit
You can use this
\b(?!\w*(\d)\w*\1)(?=(?:[a-z]+\d+)|(?:\d+[a-z]+))[a-z0-9]+\b
\b - Word boundary.
(?!\w*(\d)\w*\1) - Condition to check unique digits.
(?=(?:[a-z]+\d+)|(?:\d+[a-z]+)) - Condition to check alphanumeric words.
[a-z0-9]+ - Matches a to z and 0 to 9
Demo

regex - don't allow name to finish with hyphen

I'm trying to create a regex using javascript that will allow names like abc-def but will not allow abc-
(hyphen is also the only nonalpha character allowed)
The name has to be a minimum of 2 characters. I started with
^[a-zA-Z-]{2,}$, but it's not good enough so I'm trying something like this
^([A-Za-z]{2,})+(-[A-Za-z]+)*$.
It can have more than one - in a name but it should never start or finish with -.
It's allowing names like xx-x but not names like x-x. I'd like to achieve that x-x is also accepted but not x-.
Thanks!
Option 1
This option matches strings that begin and end with a letter and ensures two - are not consecutive so a string like a--a is invalid. To allow this case, see the Option 2.
^[a-z]+(?:-?[a-z]+)+$
^ Assert position at the start of the line
[a-z]+ Match any lowercase ASCII letter one or more times (with i flag this also matches uppercase variants)
(?:-?[a-z]+)+ Match the following one or more times
-? Optionally match -
[a-z]+ Match any ASCII letter (with i flag)
$ Assert position at the end of the line
var a = [
"aa","a-a","a-a-a","aa-aa-aa","aa-a", // valid
"aa-a-","a","a-","-a","a--a" // invalid
]
var r = /^[a-z]+(?:-?[a-z]+)+$/i
a.forEach(function(s) {
console.log(`${s}: ${r.test(s)}`)
})
Option 2
If you want to match strings like a--a then you can instead use the following regex:
^[a-z]+[a-z-]*[a-z]+$
var a = [
"aa","a-a","a-a-a","aa-aa-aa","aa-a","a--a", // valid
"aa-a-","a","a-","-a" // invalid
]
var r = /^[a-z]+[a-z-]*[a-z]+$/i
a.forEach(function(s) {
console.log(`${s}: ${r.test(s)}`)
})
You can use a negative lookahead:
/(?!.*-$)^[a-z][a-z-]+$/i
Regex101 Example
Breakdown:
// Negative lookahead so that it can't end with a -
(?!.*-$)
// The actual string must begin with a letter a-z
[a-z]
// Any following strings can be a-z or -, there must be at least 1 of these
[a-z-]+
let regex = /(?!.*-$)^[a-z][a-z-]+$/i;
let test = [
'xx-x',
'x-x',
'x-x-x',
'x-',
'x-x-x-',
'-x',
'x'
];
test.forEach(string => {
console.log(string, ':', regex.test(string));
});
The problem is that the first assertion accepts 2 or more [A-Za-z]. You will need to modify it to accept one or more character:
^[A-Za-z]+((-[A-Za-z]{1,})+)?$
Edit: solved some commented issues
/^[A-Za-z]+((-[A-Za-z]{1,})+)?$/.test('xggg-dfe'); // Logs true
/^[A-Za-z]+((-[A-Za-z]{1,})+)?$/.test('x-d'); // Logs true
/^[A-Za-z]+((-[A-Za-z]{1,})+)?$/.test('xggg-'); // Logs false
Edit 2: Edited to accept characters only
/^[A-Za-z]+((-[A-Za-z]{1,})+)?$/.test('abc'); // Logs true
Use this if you want to accept such as A---A as well :
^(?!-|.*-$)[A-Za-z-]{2,}$
https://regex101.com/r/4UYd9l/4/
If you don't want to accept such as A---A do this:
^(?!-|.*[-]{2,}.*|.*-$)[A-Za-z-]{2,}$
https://regex101.com/r/qH4Q0q/4/
So both will accept only word starting from two characters of the pattern [A-Za-z-] and not start or end (?!-|.*-$) (negative lookahead) with - .
Try this /([a-zA-Z]{1,}-[a-zA-Z]{1,})/g
I suggest the following :
^[a-zA-Z][a-zA-Z-]*[a-zA-Z]$
It validates :
that the matched string is at least composed of two characters (the first and last character classes are matched exactly once)
that the first and the last characters aren't dashes (the first and last character classes do not include -)
that the string can contain dashes and be greater than 2 characters (the second character class includes dashes and will consume as much characters as needed, dashes included).
Try it online.
^(?=[A-Za-z](?:-|[A-Za-z]))(?:(?:-|^)[A-Za-z]+)+$
Asserts that
the first character is a-z
the second is a-z or hyphen
If this matches
looks for groups of one or more letters prefixed by a hyphen or start of string, all the way to end of string.
You can also use the I switch to make it case insensitive.

JavaScript Regular Expression OR Operator

Saw a challenge on Twitter so I've been working my way through it, granted I am not the best with Regular Expressions. This is what I have so far:
var pass_regex = new RegExp(/^[a-z][A-Z][0-9]|[!##$%^&*()_]+$/);
I am trying to match a password input that contains:
1 Lowercase Letter
1 Uppercase Letter
1 Digit OR Special Character
Where I am getting stuck is on the 'OR' part, I thought the pipe separator between [0-9] and my set of special characters would work but it doesn't seem to. Trying to better understand how you would use regular expressions to to check for 1 Digit OR 1 Special Character. Thank you in advance for any help provided.
Atleast one:
You need to use a positive lookahead based regex for checking multiple conditions.
^(?=.*?[A-Z])(?=.*?[a-z]).*?[\W\d].*
OR
^(?=.*?[A-Z])(?=.*?[a-z]).*?[!##$%^&*()_\d].*
(?=.*?[A-Z]) Asserts that there must be atleast one uppercase letter.
(?=.*?[a-z]) Atleast one lowercase letter.
.*? non-greedy match of any character zero or more times.
If the above conditions are satisfied then match that corresponding string and also the string must contain atleast a single character from the given list [!##$%^&*()_\d] . \d in this list matches any digit character.
.* matches the following zero or more characters.
DEMO

validating variable in javascript

Hi i have a field in php that will be validated in javascript using i.e for emails
var emailRegex = /^[\w-\.]+#([\w-]+\.)+[\w-]{2,4}$/;
What i'm after is a validation check which will look for the
first letter as a capital Q
then the next letters can be numbers only
then followed by a .
then two numbers only
and then an optional letter
i.e Q100.11 or Q100.11a
I must admit i look at the above email validation check and i have no clue how it works but it does ;)
many thanks for any help on this
Steve
The ^ marks the beginning of the string, $ matches the end of the string. In other words, the whole string should exactly match this regular expression.
[\w-\.]+: I think you wanted to match letters, digits, dots and - only. In that case, the - should be escaped (\-): [\w\-\.]+. The plus-sign makes is match one or more times.
#: a literal # match
([\w-]+\.)+ letters, digits and - are allowed one or more times, with a dot after it (between the parentheses). This may occur several times (at least once).
[\w-]{2,4}: this should match the TLD, like com, net or org. Because a TLD can only contain letters, it should be replaced by [a-z]{2,4}. This means: lowercase letters may occur two till four times. Note that the TLD can be longer than 4 characters.
An regular expression which should follow the next rules:
a capital Q (Q)
followed by one or more occurrences of digits (\d+)
a literal dot (.)
two digits (\d{2})
one optional letter ([a-z]?)
Result:
var regex = /Q\d+\.\d{2}[a-z]?/;
If you need to match strings case-insensitive, add the i (case-insensitive) modifier:
var regex = /Q\d+\.\d{2}[a-z]?/i;
Validating a string using a regexp can be done in several ways, one of them:
if (regex.test(str)) {
// success
} else {
// no match
}
var emailRegex = /^Q\d+\.\d{2}[a-zA-Z]?#([\w-]+\.)+[a-zA-Z]+$/;
var str = "Q100.11#test.com";
alert(emailRegex.test(str));
var regex = /^Q[0-9]+\.[0-9]{2}[a-z]?$/;
+ means one or more
the period must be escaped - \.
[0-9]{2} means 2 digits, same as \d{2}
[a-z]? means 0 or 1 letter
You can check your regex at http://regexpal.com/

Regex to match '-' delimited alphanumeric words

I would like to test if user type only alphanumeric value or one "-".
hello-world -> Match
hello-first-world -> match
this-is-my-super-world -> match
hello--world -> NO MATCH
hello-world-------this-is -> NO MATCH
-hello-world -> NO MATCH (leading dash)
hello-world- -> NO MATCH (trailing dash)
Here is what I have so far, but I dont know how to implement the "-" sign to test it if it is only once without repeating.
var regExp = /^[A-Za-z0-9-]+$/;
Try this:
/^[A-Za-z0-9]+(?:-[A-Za-z0-9]+)*$/
This will only match sequences of one or more sequences of alphanumeric characters separated by a single -. If you do not want to allow single words (e.g. just hello), replace the * multiplier with + to allow only one or more repetitions of the last group.
Here you go (this works).
var regExp = /^[A-Za-z0-9]+([-]{1}[A-Za-z0-9]+)+$/;
letters and numbers greedy, single dash, repeat this combination, end with letters and numbers.
(^-)|-{2,}|[^a-zA-Z-]|(-$) looks for invalid characters, so zero matches to that pattern would satisfy your requirement.
I'm not entirely sure if this works because I haven't done regex in awhile, but it sounds like you need the following:
/^[A-Za-z0-9]+(-[A-Za-z0-9]+)+$/
You're requirement is split up in the following:
One or more alphanumeric characters to start (that way you ALWAYS have an alphanumeric starting.
The second half entails a "-" followed by one or more alphanumeric characters (but this is optional, so the entire thing is required 0 or more times). That way you'll have 0 or more instances of the dash followed by 1+ alphanumeric.
I'm just not sure if I did the regex properly to follow that format.
The expression can be simplified to: /^[^\W_]+(?:-[^\W_]+)+$/
Explanation:
^ match the start of string
[^\W_]+ match one or more word(a-zA-Z0-9) chars
(?:-[^\W_]+)+ match one or more group of '-' follwed by word chars
$ match the end of string
Test: https://regex101.com/r/MODQxw/1

Categories