Regex to allow * only after a certain position in the string - javascript

I have an input field in the UI which must satisfy the following three conditions.
The input string can be a max of 20 chars long and will be alphanumeric.
However it can have * but only after 6th character, no other special characters allowed.
Eg. Abc123* or Abc1234* or just Abc1234(until 20 chars)
The overall length of string is 20 chars but as soon as we encounter * we should not allow any further characters
I understand the 3rd condition can be a bit too much of an ask for regex and I should be able to handle that using javascript.
However I at least want to get the first 2 conditions resolved using regex.
I have tried few stuffs below but they don’t give the desired results:
export function formatInput(value) {
return value
.replace(/[^\w*]|_/g, '')
.replace(new RegExp('(^[\\w]{6})([\\w*]{14}$)’, 'g'), '$1');
}
I tried to tweak few things, like if I remove the first replace statement it doesn’t filter out any special characters at all.
Also in the below case it restricts me to enter * as 7th character before allowing me to proceed further which is also incorrect.
export function formatInput(value) {
return value
.replace(/[^\w*]|_/g, '')
.replace(new RegExp('(^[\\w]{6})[\\w]', 'g'), '$1')
.replace(/(\..*)\./g, '$1')
.replace(new RegExp('(\\*[\\w]{14}).', 'g'), '$1');
}
I am trying to enhance my knowledge about regex, so my above attempts might not be correct, any help will be highly appreciated.

I'm a bit confused with your attempt to replace, so let me just share a pattern that should tick the 3 boxes you described:
^(?!.{21}|.{1,5}\*)[A-Za-z\d]+\*?$
See the online demo
^ - Start line anchor.
(?!.{21}|.{1,5}\*) - Negative lookahead with alternation to prevent position is followed by 21 characters or 1-5 characters before the asterisks.
[A-Za-z\d]+ - 1+ Alphanumeric chars.
\*? - An optional asterisks.
$ - End line anchor.
Note that you could also use case-insensitive flag as an alternative and use ^(?!.{21}|.{1,5}\*)[A-Z\d]+\*?$.

Something like this would work:
/^(?:[a-z\d]{6,19}\*|[a-z\d]{1,20})$/gmi
^ - start line anchor
(?: - start non-capturing group
[a-z\d]{6,19}\* - we can have 6 to 19 alphanums followed by one asterisk
| - boolean or
[a-z\d]{1,20} - we can have 1 to 20 alphanums
) - end non-capturing group
$ - end line anchor
/gmi - flags: global, multiline, case-insensitive
g and m are only needed for regex101 purposes so that you can test out multiple inputs at once
https://regex101.com/r/ytMlQO/1/

The following pattern satisfies all your conditions. This pattern assumes there is no other content in value aside from the password to be checked. I also share the concern about performing manipulations a la replace in a function that is supposed to be purely for verification, so I've written the function below to simply test to ensure conformance with the prescribed pattern.
const passwordPattern = /^[A-Za-z\d]{6}(?:[A-Za-z\d]|\*(?!.+)){0,14}$/;
const checkPassword = value => passwordPattern.test(value);
console.log(checkPassword("Abc123")); // true
console.log(checkPassword("Abc123*")); // true
console.log(checkPassword("Abc12*")); // false - asterisk appears before position 6
console.log(checkPassword("Abc123*4")); // false - other characters appear after asterisk
console.log(checkPassword("123456789012345678901")); // false - >20 characters in length
Regex101

Related

Regular Expression Strict Test

I am trying to create regex where user have to enter exactly the same thing no extra no less
Here is my regex;
/[a-zA-Z0-9][a-zA-Z0-9\-]*\.myshopify\.com/
when I test this with, for example, myshop.myshopify.coma it returns true or myshop.myshopify.com myshop123.myshopify.com still returns true
What I am trying to get is if user enters myshop.myshopify.coma or myshop321.myshopify.com myshop123.myshopify.coma it shouldn't be match.
It should only match when the entire input is exactly like this [anything except ()=>%$ etc].myshopify.com
what should I include in my regex to strictly test exactly one thing.
you can use boundary-type assertions to match the beginning of an input (^) and an end ($) - to make sure your input matches fully.
const pattern = /^[a-zA-Z0-9][a-zA-Z0-9\-]*\.myshopify\.com$/
console.log(pattern.test('myshop.myshopify.com')) // true
console.log(pattern.test('myshop.myshopify.coma')) // false
console.log(pattern.test('myshop.myshopify.com myshop123.myshopify.com')) // false
You'd currently allow for input like "A---", so besides the good point about start and end line anchors, you'd maybe want to reconsider your pattern. Maybe something like:
^[a-z\d]+(?:-[a-z\d]+)*\.myshopify\.com$
See the online demo
^ - Start line anchor.
[a-z\d]+ - 1+ any alnum character.
(?: - Open non-capture group:
-[a-z\d]+ - A literal hyphen followed by 1+ alnum chars.
)* - Close non-capture group and match it zero or more times.
\.myshopify\.com - Match a ".myshopify.com" literallyy.
$ - End line anchor.
A 2nd option would be to use a negative lookahead to achieve the same concept:
^(?!-|.*-[-.])[a-z\d-]+\.myshopify\.com$
See the online demo
^ - Start line anchor.
(?! - Negative lookahead for:
- - A leading hypen
| - Or:
.*-[-.] - Any character other than newline zero or more times up to an hypen with either another hypen or a literal dot.
) - Close negative lookahead.
[a-zA-Z\d]+ - 1+ any alnum character.
\.myshopify\.com - Match a ".myshopify.com" literallyy.
$ - End line anchor.
In both cases I used both the global and case-insensitive flags: /<pattern>/gi. See a sample below:
const patt1 = /^[a-z\d]+(?:-[a-z\d]+)*\.myshopify\.com$/gi
console.log(patt1.test('myshop.myshopify.com'))
console.log(patt1.test('myshop-.myshopify.com'))
const patt2 = /^(?!-|.*-[-.])[a-z\d-]+\.myshopify\.com$/gi
console.log(patt2.test('myshop.myshopify.com'))
console.log(patt2.test('myshop-.myshopify.com'))

Check for a specific suffix by RegEx and select entire match including suffix

First of all, this is my first question in the community hence please pardon my wrongs Experts! I am learning regex and faced a scenario where I am failing to create answer by myself.
Let's say if there is humongous paragraph, can we first match on the basis of a specific suffix (say '%') and Only then go back and select the desired logic including suffix?
e.g. part of the text is "abcd efghMNP 0.40 % ijkl mnopSNP -3.20 % xyz".
Now in this, if you notice - and I got this much - that there is pattern like /([MS]NP[\s\d\.-%]+)/
I want to replace "MNP 0.40 %" or "SNP -3.20 %" with blank. replacing part seems easy :) But the problem is with all my learning I am not able to select desired ONLY IF there exists a '%' at the end of match.
The sequence of match I wish to reach at is -- if suffix '%' exists, then match the previous pattern, and if successful then select everything including suffix and replace with empty.
There are several expressions that would do so, for instance this one with added constraints:
[A-Z]{3}\s+[-+]?[0-9.]+\s*%
Test
const regex = /[A-Z]{3}\s+[-+]?[0-9.]+\s*%/gm;
const str = `abcd efghMNP 0.40 % ijkl mnopSNP -3.20 % xyz
"MNP 0.40 %" or "SNP -3.20 %"`;
const subst = ``;
// The substituted value will be contained in the result variable
const result = str.replace(regex, subst);
console.log(result);
Demo 1
Or a simplified version would be:
[A-Z]{3}(.*?)%
Demo 2
You can not go back in the matching if you have encountered a suffix %, but what you can do is to make it part of the pattern so that is has to be matched.
In Javascript you could perform a zero length lookahead assertion (?= making sure that what is on the right contains a pattern or in this case a % but that will not be a real benefit in this case as you want it to be part of the match.
A bit more specific match could be:
[MS]NP\s*-?\d+(?:\.\d+)?\s*%
[MS]NP Match M or S followed by NP
\s*-? Match 0+ times a whitespace char followed by an optional -
\d+(?:\.\d+)? Match 1+ digits followed by an optional part to match a dot and 1+ digits
\s*% Match 0+ whitespace chars followed by matching %
Regex demo

regular expression, not reading entire string

I have a standard expression that is not working correctly.
This expression is supposed to catch if a string has invalid characters anywhere in the string. It works perfect on RegExr.com but not in my tests.
The exp is: /[a-zA-Z0-9'.\-]/g
It is failing on : ####
but passing with : aa####
It should fail both times, what am I doing wrong?
Also, /^[a-zA-Z0-9'.\-]$/g matches nothing...
//All Boxs
$('input[type="text"]').each(function () {
var text = $(this).prop("value")
var textTest = /[a-zA-Z0-9'.\-]/g.test(text)
if (!textTest && text != "") {
allFieldsValid = false
$(this).css("background-color", "rgba(224, 0, 0, 0.29)")
alert("Invalid characters found in " + text + " \n\n Valid characters are:\n A-Z a-z 0-9 ' . -")
}
else {
$(this).css("background-color", "#FFFFFF")
$(this).prop("value", text)
}
});
edit:added code
UPDATE AFTER QUESTION RE-TAGGING
You need to use
var textTest = /^[a-zA-Z0-9'.-]+$/.test(text)
^^
Note the absence of /g modifier and the + quantifier. There are known issues when you use /g global modifier within a regex used in RegExp#test() function.
You may shorten it a bit with the help of the /i case insensitive modifier:
var textTest = /^[A-Z0-9'.-]+$/i.test(text)
Also, as I mention below, you do not have to escape the - at the end of the character class [...], but it is advisable to keep escaped if the pattern will be modified later by less regex-savvy developers.
ORIGINAL C#-RELATED DETAILS
Ok, say, you are using Regex.IsMatch(str, #"[a-zA-Z0-9'.-]"). The Regex.IsMatch searches for partial matches inside a string. So, if the input string contains an ASCII letter, digit, ', . or -, this will pass. Thus, it is logical that aa#### passes this test, and #### does not.
If you use the second one as Regex.IsMatch(str, #"^[a-zA-Z0-9'.-]$"), only 1 character strings (with an optional newline at the end) would get matched as ^ matches at the start of the string, [a-zA-Z0-9'.-] matches 1 character from the specified ranges/sets, and $ matches the end of the string (or right before the final newline).
So, you need a quantifier (+ to match 1 or more, or * to match zero or more occurrences) and the anchors \A and \z:
Regex.IsMatch(str, #"\A[a-zA-Z0-9'.-]+\z")
^^ ^^^
\A matches the start of string (always) and \z matches the very end of the string in .NET. The [a-zA-Z0-9'.-]+ will match 1+ characters that are either ASCII letters, digits, ', . or -.
Note that - at the end of the character class does not have to be escaped (but you may keep the \- if some other developers will have to modify the pattern later).
And please be careful where you test your regexps. Regexr only supports JavaScript regex syntax. To test .NET regexps, use RegexStorm.net or RegexHero.
/^[a-zA-Z0-9'.-]+$/g
In the second case your (/[a-zA-Z0-9'.-]/g) was working because it matched on the first letter, so to make it correct you need to match the whole string (use ^ and $) and also allow more letters by adding a + or * (if you allow empty string).
Try this regex it matches any char which isn't part of the allowed charset
/[^a-zA-Z0-9'.\-]+/g
Test
>>regex = /[^a-zA-Z0-9'.\-]+/g
/[^a-zA-Z0-9'.\-]+/g
>>regex.test( "####dsfdfjsakldfj")
true
>>regex.test( "dsfdfjsakldfj")
false

Query on Javascript RegEx

I need a regex that allows 0-9, a-z, A-Z, hyphen, question mark and "/" slash characters alone. Also the length should be between 5 to 15 only.
I tried as follows, but it does not work:
var reg3 = /^([a-zA-Z0-9?-]){4,15}+$/;
alert(reg3.test("abcd-"));
length should be between 5 to 15 only
Is that why you have this?
{4,15}+
Just use {5,15}; it’s already a quantifier, and a + after it won’t work. Apart from that, the group isn’t necessary, but things should work.
/^[a-zA-Z0-9?/-]{5,15}$/
(I also added a slash character.)
This is what you need:
if (/^([a-z\/?-]{4,15})$/i.test(subject)) {
// Successful match
} else {
// Match attempt failed
}
REGEX EXPLANATION
^([a-z\/?-]{4,15})$
Options: Case insensitive
Assert position at the beginning of the string «^»
Match the regex below and capture its match into backreference number 1 «([a-z\/?-]{4,15})»
Match a single character present in the list below «[a-z\/?-]{4,15}»
Between 4 and 15 times, as many times as possible, giving back as needed (greedy) «{4,15}»
A character in the range between “a” and “z” (case insensitive) «a-z»
The literal character “/” «\/»
The literal character “?” «?»
The literal character “-” «-»
Assert position at the very end of the string «$»
Couple issues,
you need {5,15} instead of {4,15}+
need to include /
Your code can be rewritten as
var reg3 = new RegExp('^[a-z0-9?/-]{5,15}$', 'i'); // i flag to eliminate need of A-Z
alert(reg3.test("a1?-A7="));
Update
Let's not confuse can be with MUST be and concentrate on the actual thing I was trying to convey.
{4,15}+ part in /^([a-zA-Z0-9?-]){4,15}+$/ should be written as {5,15}, and / must be included; which will make your regexp
/^([a-zA-Z0-9?/-]){5,15}$/
which CAN be written as
/^[a-z0-9?/-]{5,15}$/i // i flag to eliminate need of A-Z
Also I hope everybody is OK with use of /i

password validation using javascript

I need to match a password field using javascript with the following requirements:
Should be alpha numaric with at least one special character.
no spaces to be allowed
should be minimum 10 char and max 20 chars.
No repeate of char more than 2 times.
~,'.:;^| are not allowed
I have a regex
var password = /^(?=.[0-9])(?=.[!##$%^&])[a-zA-Z0-9!##$%^&]{10,20}$/;
how can i solve this?
This might be the required regex
^(?=.*[!##$%^&])(?!.*(.).*\1.*\1)[A-Za-z\d!##$%^&|]{10,20}$
(?=.*[!##$%^&]) ensures at least one occurrence of the listed characters.
(?!.*(.).*\1.*\1) ensures no character is repeated more than twice.
[A-Za-z\d!##$%^&|]{10,20} matches 10-20 occurrence of characters from the character class.
I would write separate rules (probably using regex for all of them - for consistency - unless performance is a great concern) that each relate directly to a rule on your list.
The code
var pw = "asddfak#kjg";
/* Should be alpha numaric with at least one special character. */
console.log(null !== pw.match(/[#+#$]/));
/* no spaces to be allowed */
console.log(null !== pw.match(/^\S+$/));
/* should be minimum 10 char and max 20 chars. */
console.log(null !== pw.match(/^.{10,20}$/));
/* No repeate of char more than 2 times. */
console.log(null === pw.match(/(.)(.*\1){2}/));
/* ~,'.:;^| are not allowed */
console.log(null !== pw.match(/^[^~,'.:;^|]+$/));
Although it is possible to make the regex more concise, I think it is much more maintainable to make the rules more literal to your intent. If performance is a significant issue (usually not for this kind of thing) then I would avoid regex, and implement the rules using string methods.
Regex Explained
/ // start regex pattern
[ // open character class
#+#$ // match one of these `special` characters
] // close character class
/ // end regex pattern
/ // start regex pattern
^ // start matched string
\S+ // one or more (`+`) not spaces (`\S`)
$ // end matched string
/ // end regex pattern
/ // start regex pattern
^ // start matched string
.{10,20} // between 10 and 20 of any character (`.`)
$ // end matched string
/ // end regex pattern
/ // start regex pattern
(.) // any character captured as group 1
(.*\1){2} // followed by zero or more of anything (`\.*`) and then the captured group 1 (`\1`) two times (`{2}`)
/ // end regex pattern
/ // start regex pattern
^ // start matched string
[ // open character class
^~,'.:;^| // not (`^`) one of these characters
]+ // close character class
$ // end matched string
/ // end regex pattern
p.s. you should keep a lot of comments with regex you use, because unlike books, they are much easier written than read
This should work:
/^(?=.*?[!##$%^&])(?:([a-zA-Z0-9!##$%^&])(?!.*?\1.*?\1)){10,20}$/
(if by repeat more than 2 times you mean the same character can't appear thrice)
Explanation:
1st condition: at the very beginning, we'll go through the whole string a first time until we find a special character, as soon as we have it, we stop, if we don't, it fails (Source): (?=.*?[!##$%^&])
2nd condition: nothing to do, [a-zA-Z0-9!##$%^&] doesn't allow spaces anyway
3rd condition: quantifier: {10,20}
4th condition: the subtle one: as we get through the string, for each character captured, we check the it's not repeated twice more (same source): (?!.*?\1.*?\1)
5th condition: same as whitespaces
based on your 5 things in your requirements this is exact pattern you need
^(?=.*[!##$%^&])(?!.*(.).*\1.*\1)[^\s~,'.:;^|]{10,20}$

Categories

Resources