Input string test with a regex in JavaScript - javascript

I am trying to test a input string of format AWT=10:15;, based on this regex that I wrote: (([AWT]\w\S=)?(\d{0,9}:)?(\d{0,9});).
Problem 1: I am receiving this error: Uncaught TypeError: Cannot read property '0' of undefined when I try to match the string with the regex.
Problem 2: The string seems to come off as valid even after I enter this: AWT=10:15;12 which shouldn't be the case.
Here is my code:
var reg = new RegExp('(([AWT]\w\S=)?(\d{0,9}:)?(\d{0,9});)');
var x = $('td').find('.awt')[0].value;
console.log(x); // AWT=10:15;
console.log(String(x).match(reg)); // [";", ";", undefined, undefined, "", index: 9, input: "AWT=10:15;", groups: undefined]
if(String(x).match(reg)){
console.log("valid");
}else{
console.log("Invalid")
}
I was wondering if anyone can help me figure out the right regex for the string.
PS: The string needs to be in that exact format: (AWT=[0,9]:[0,9];).

Your regex (([AWT]\w\S=)?(\d{0,9}:)?(\d{0,9});) means:
( # start group 1
( # start group 2
[AWT] # 1 character A or W or T
\w # 1 word character <=> [A-Za-z0-9_]
\S # 1 non space character
= # equal sign
)? # end group 2, optional
( # start group 3
\d{0,9} # from 0 upto 9 digits
: # colon
)? # end group 3, optional
( # start group 4
\d{0,9} # from 0 upto 9 digits
) # end group 4
; # semicolon
) # end group 1
It matches AWT=10:15; as well as:
blahAWT=123456789:123456789;blah
Wx!=123;
12345;
Not sure it's what you want!
According to your requierement “The string needs to be in that exact format: AWT=[0,9]:[0,9];”, this regex will do the job: ^AWT=\d\d:\d\d;$
Explanation:
^ # beginning of string
AWT= # literally AWT=
\d\d # 2 digits
: # a colon
\d\d # 2 digits
; # a semicolon
$ # end of string
Use it this way:
var reg = new RegExp('^AWT=\\d\\d:\\d\\d;$');
or, better:
var reg = /^AWT=\d\d:\d\d;$/;

#user120242 is totally right about the cause of your bug.
I just want to add another option instead of escaping the characters. If you use /someRegex/ this is not necessary.
Moreover, if you are always expecting AWT at the beginning, this ([AWT]\w\S=) is not optimal. It means: either A, W or T, then a word character, then a non space character and then =. If it always starts with AWT= use (AWT=).
var reg = /(([AWT]\w\S=)?(\d{0,9}:)?(\d{0,9});)/
var x = $('td').find('.awt')[0].value;
console.log(x); // AWT=10:15;
console.log(String(x).match(reg));
if (String(x).match(reg)) {
console.log("valid");
} else {
console.log("Invalid")
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table>
<tr>
<td><input class="awt" value="AWT=10:15;"></td>
</tr>
</table>

You need to escape backslashes in the string, or \w becomes w
You need to use ^$ to match on beginning and end, so it only matches if the full string matches
Another option depending on what you are trying to do, is to use negative lookahead (?!.*)
or a capture group behind the last (;.*) where you would check matches for the final match group for content and reject based on that.
console.log('(([AWT]\w\S=)?(\d{0,9}:)?(\d{0,9});)'); // this is not what you want
function matcher(){
var reg = new RegExp('^(([AWT]\\w\\S=)?(\\d{1,9}:)?(\\d{1,9});)$');
var x = $('td').find('input')[0].value;
console.log(x); // AWT=10:15;
console.log(x.match(reg)); // [";", ";", undefined, undefined, "", index: 9, input: "AWT=10:15;", groups: undefined]
if (reg.test(x)) {
console.log("valid");
} else {
console.log("Invalid")
}
}
matcher();
$('td').find('input').on('input',matcher);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table><tr>
<td><input class="awt" value="AWT=10:15;"></td></tr></table>

Related

JavaScript Alphanumeric Regex and allow asterisk at the start of the string but do not allow asterisk at the last 4 digits of the string

I have this regex ^[a-zA-Z0-9*]+$ for only allowing alphanumeric chars and allow Asterisk(*). But I would like allow asterisk only at the start of the string. But asterisk is not allowed at the last 4 digits of the string.
new RegExp('^[a-zA-Z0-9*]+$').test('test') ---Valid
new RegExp('^[a-zA-Z0-9*]+$').test('test1234') --Valid
new RegExp('^[a-zA-Z0-9*]+$').test('test##_')--Invalid
new RegExp('^[a-zA-Z0-9*]+$').test('****1234') --Valid
new RegExp('^[a-zA-Z0-9*]+$').test('*tes**1234') --Valid
new RegExp('^[a-zA-Z0-9*]+$').test('test****') --Should be Invalid
"How would I allow Asterisk only at the start of the string?" But if the asterisk presents in any of the last 4 positions then it should be invalid
You can use this regex to allow only alphanumeric chars and asterisk, but no asterisk at the last 4 char positions:
const regex = /^(?:[a-z\d*]*[a-z\d]{4}|[a-z\d]{1,3})$/i;
[
'1',
'12',
'test',
'test1234',
'****1234',
'*tes**1234',
'*1*2345',
'test##_',
'test****',
'test***5',
'test**4*',
'*3**'
].forEach(str => {
let result = regex.test(str);
console.log(str, '==>', result);
});
Output:
1 ==> true
12 ==> true
test ==> true
test1234 ==> true
****1234 ==> true
*tes**1234 ==> true
*1*2345 ==> true
test##_ ==> false
test**** ==> false
test***5 ==> false
test**4* ==> false
*3** ==> false
Explanation of regex:
^ -- anchor at start of string
(?: -- start non-capture group (for logical OR)
[a-z\d*]*[a-z\d]{4} -- allow alphanumeric chars and asterisk, followed by 4 alphanumeric chars
| -- logical OR
[a-z\d]{1,3} -- allow 1 to 3 alphanumeric chars
) -- close group
$ -- anchor at end of string
Not that it is easier to read and more efficient to use /.../ instead of new RegExp("..."). You need the regex constructor only if you have variable input.

What will be the best regex Expression for censoring email?

Hello I am stuck on a problem for censoring email in a specific format, but I am not getting how to do that, please help me!
Email : exampleEmail#example.com
Required : e***********#e******.com
Help me getting this in javascript,
Current code I am using to censor :
const email = exampleEmail#example.com;
const regex = /(?<!^).(?!$)/g;
const censoredEmail = email.replace(regex, '*');
Output: e**********************m
Please help me getting e***********#e******.com
You can use
const email = 'exampleEmail#example.com';
const regex = /(^.|#[^#](?=[^#]*$)|\.[^.]+$)|./g;
const censoredEmail = email.replace(regex, (x, y) => y || '*');
console.log(censoredEmail );
// => e***********#e******.com
Details:
( - start of Group 1:
^.| - start of string and any one char, or
#[^#](?=[^#]*$)| - a # and any one char other than # that are followed with any chars other than # till end of string, or
\.[^.]+$ - a . and then any one or more chars other than . till end of string
) - end of group
| - or
. - any one char.
The (x, y) => y || '*' replacement means the matches are replaced with Group 1 value if it matched (participated in the match) or with *.
If there should be a single # present in the string, you can capture all the parts of the string and do the replacement on the specific groups.
^ Start of string
([^\s#]) Capture the first char other than a whitespace char or # that should be unmodified
([^\s#]*) Capture optional repetitions of the same
# Match literally
([^\s#]) Capture the first char other than a whitespace char or # after it that should be unmodified
([^\s#]*) Capture optional repetitions of the same
(\.[^\s.#]+) Capture a dot and 1+ other chars than a dot, # or whitespace char that should be unmodified
$ End of string
Regex demo
In the replacement use all 5 capture groups, where you replace group 2 and 4 with *.
const regex = /^([^\s#])([^\s#]*)#([^\s#])([^\s#]*)(\.[^\s.#]+)$/;
[
"exampleEmail#example.com",
"test"
].forEach(email =>
console.log(
email.replace(regex, (_, g1, g2, g3, g4, g5) =>
`${g1}${"*".repeat(g2.length)}#${g3}${"*".repeat(g4.length)}${g5}`)
)
);

Regex to validate a comma separated list of unique numbers

I am trying to validate a comma separated list of numbers 1-7 unique (not repeating).
i.e.
2,4,6,7,1 is valid input.
2,2,6 is invalid
2 is valid
2, is invalid
1,2,3,4,5,6,7,8 is invalid ( only 7 number)
I tried ^[1-7](?:,[1-7])*$ but it's accepting repeating numbers
var data = [
'2,4,6,7,1',
'2,2,6',
'2',
'2,',
'1,2,3,2',
'1,2,2,3',
'1,2,3,4,5,6,7,8'
];
data.forEach(function(str) {
document.write(str + ' gives ' + /(?!([1-7])(?:(?!\1).)\1)^((?:^|,)[1-7]){1,7}$/.test(str) + '<br/>');
});
Regex are not suited for this. You should split the list into an array and try the different conditions:
function isValid(list) {
var arrList = list.split(",");
if (arrList.length > 7) { // if more than 7, there are duplicates
return false;
}
var temp = {};
for (var i in arrList) {
if (arrList[i] === "") return false; // if empty element, not valid
temp[arrList[i]] = "";
}
if (Object.keys(temp).length !== arrList.length) { // if they're not of same length, there are duplicates
return false;
}
return true;
}
console.log(isValid("2,4,6,7,1")); // true
console.log(isValid("2,2,6")); // false
console.log(isValid("2")); // true
console.log(isValid("2,")); // false
console.log(isValid("1,2,3,4,5,6,7,8")); // false
console.log(isValid("1,2,3")); // true
console.log(isValid("1,2,3,7,7")); // false
No RegEx is needed:
This is much more maintainable and explicit than a convoluted regular expression would be.
function isValid(a) {
var s = new Set(a);
s.delete(''); // for the hanging comma case ie:"2,"
return a.length < 7 && a.length == s.size;
}
var a = '2,4,6,7,1'.split(',');
alert(isValid(a)); // true
a = '2,2,6'.split(',');
alert(isValid(a)); // false
a = '2'.split(',');
alert(isValid(a)); // true
a = '2,'.split(',');
alert(isValid(a)); // false
'1,2,3,4,5,6,7,8'.split(',');
alert(isValid(a)); // false
You were pretty close.
^ # BOS
(?! # Validate no dups
.*
( [1-7] ) # (1)
.*
\1
)
[1-7] # Unrolled-loop, match 1 to 7 numb's
(?:
,
[1-7]
){0,6}
$ # EOS
var data = [
'2,4,6,7,1',
'2,2,6',
'2',
'2,',
'1,2,3,2',
'1,2,2,3',
'1,2,3,4,5,6,7,8'
];
data.forEach(function(str) {
document.write(str + ' gives ' + /^(?!.*([1-7]).*\1)[1-7](?:,[1-7]){0,6}$/.test(str) + '<br/>');
});
Output
2,4,6,7,1 gives true
2,2,6 gives false
2 gives true
2, gives false
1,2,3,2 gives false
1,2,2,3 gives false
1,2,3,4,5,6,7,8 gives false
For a number range that exceeds 1 digit, just add word boundary's around
the capture group and the back reference.
This isolates a complete number.
This particular one is numb range 1-31
^ # BOS
(?! # Validate no dups
.*
( # (1 start)
\b
(?: [1-9] | [1-2] \d | 3 [0-1] ) # number range 1-31
\b
) # (1 end)
.*
\b \1 \b
)
(?: [1-9] | [1-2] \d | 3 [0-1] ) # Unrolled-loop, match 1 to 7 numb's
(?: # in the number range 1-31
,
(?: [1-9] | [1-2] \d | 3 [0-1] )
){0,6}
$ # EOS
var data = [
'2,4,6,7,1',
'2,2,6',
'2,30,16,3',
'2,',
'1,2,3,2',
'1,2,2,3',
'1,2,3,4,5,6,7,8'
];
data.forEach(function(str) {
document.write(str + ' gives ' + /^(?!.*(\b(?:[1-9]|[1-2]\d|3[0-1])\b).*\b\1\b)(?:[1-9]|[1-2]\d|3[0-1])(?:,(?:[1-9]|[1-2]\d|3[0-1])){0,6}$/.test(str) + '<br/>');
});
Like other commenters, I recommend you to use something other than regular expressions to solve your problem.
I have a solution, but it is too long to be a valid answer here (answers are limited to 30k characters). My solution is actually a regular expression in the language-theory sense, and is 60616 characters long. I will show you here the code I used to generate the regular expression, it is written in Python, but easily translated in any language you desire. I confirmed that it is working in principle with a smaller example (that uses only the numbers 1 to 3):
^(2(,(3(,1)?|1(,3)?))?|3(,(1(,2)?|2(,1)?))?|1(,(3(,2)?|2(,3)?))?)$
Here's the code used to generate the regex:
def build_regex(chars):
if len(chars) == 1:
return list(chars)[0]
return ('('
+
'|'.join('{}(,{})?'.format(c, build_regex(chars - {c})) for c in chars)
+
')')
Call it like this:
'^' + build_regex(set("1234567")) + "$"
The concept is the following:
To match a single number a, we can use the simple regex /a/.
To match two numbers a and b, we can match the disjunction /(a(,b)?|b(,a)?)/
Similarily, to match n numbers, we match the disjunction of all elements, each followed by the optional match for the subset of size n-1 not containing that element.
Finally, we wrap the expression in ^...$ in order to match the entire text.
Edit:
Fixed error when repeating digit wasn't the first one.
One way of doing it is:
^(?:(?:^|,)([1-7])(?=(?:,(?!\1)[1-7])*$))+$
It captures a digit and then uses a uses a look-ahead to make sure it doesn't repeats itself.
^ # Start of line
(?: # Non capturing group
(?: # Non capturing group matching:
^ # Start of line
| # or
, # comma
) #
([1-7]) # Capture digit being between 1 and 7
(?= # Positive look-ahead
(?: # Non capturing group
, # Comma
(?!\1)[1-7] # Digit 1-7 **not** being the one captured earlier
)* # Repeat group any number of times
$ # Up to end of line
) # End of positive look-ahead
)+ # Repeat group (must be present at least once)
$ # End of line
var data = [
'2,4,6,7,1',
'2,2,6',
'2',
'2,',
'1,2,3,4,5,6,7,8',
'1,2,3,3,6',
'3,1,5,1,8',
'3,2,1'
];
data.forEach(function(str) {
document.write(str + ' gives ' + /^(?:(?:^|,)([1-7])(?=(?:,(?!\1)[1-7])*$))+$/.test(str) + '<br/>');
});
Note! Don't know if performance is an issue, but this does it in almost half the number of steps compared to sln's solution ;)

Inverting a rather complex set of regexes

I'm sort of new to regular expressions, and none of the solutions I found online helped/worked.
I'm dealing with a one-line String in JavaScript, it'll contain five types of data mixed in.
A "#" followed by six numbers/letters (HTML color) (/#....../g)
A forward slash followed by any of a few specific characters (/\/(\+|\^|\-|#|!\+|_|#|\*|%|&|~)/g)
A "$" followed by a sequence of letters and a "|" (/\$([^\|]+)/g)
A "|" alone (/\|/g)
Alphanumeric characters that do not fall under any of these categories
The thing is, I have regexes to match the first four categories, that are important.
The problem is that I need a single Regex that I'll use to replace all the characters that DO NOT match for the first four regexes with a single character, such as "§".
Example:
This#00CC00 is green$Courier| and /^mono|spaced
§§§§#00CC00§§§§§§§§§$Courier|§§§§§/^§§§§|§§§§§§
I know I may be attacking this problem the wrong way, I'm rather new to regular expressions.
Essentially, how do I make a regex that means "anything that doesn't have any matches for regexes x, y, or z"?
Thank you for your time.
use this pattern
((#\w{6}|\/[\/\(\+\^\-]|\$\w+\||\|)*).
and replace w/ $1§
Downside is your preserved pattern has to be followed by at least one character
Demo
( # Capturing Group (1)
( # Capturing Group (2)
# # "#"
\w # <ASCII letter, digit or underscore>
{6} # (repeated {6} times)
| # OR
\/ # "/"
[\/\(\+\^\-] # Character Class [\/\(\+\^\-]
| # OR
\$ # "$"
\w # <ASCII letter, digit or underscore>
+ # (one or more)(greedy)
\| # "|"
| # OR
\| # "|"
) # End of Capturing Group (2)
* # (zero or more)(greedy)
) # End of Capturing Group (1)
. # Any character except line break
Code copied from Regex101
var re = /((#\w{6}|\/[\/\(\+\^\-]|\$\w+\||\|)*)./gm;
var str = 'This#00CC00 is green$Courier| and /^mono|spaced|\n';
var subst = '$1§';
var result = str.replace(re, subst);
This isn't as efficient as a working regular expression but it works. Basically it gets all of the matches and fills the parts between with § characters. One nice thing is you don't have to be a regular expression genius to update it, so hopefully more people can use it.
var str = 'This#00CC00 is green$Courier| and /^mono|spaced';
var patt=/#(\d|\w){6}|\/(\+|\^|\-|#|!\+|_|#|\*|%|&|~)|\$([^\|]+)\||\|/g;
var ret = "";
pos = [];
while (match=patt.exec(str)) {
pos.push(match.index);
pos.push(patt.lastIndex);
console.log(match.index + ' ' + patt.lastIndex);
}
for (var i=0; i<pos.length; i+=2) {
ret += Array(1+pos[i]- (i==0 ? 0 : pos[i-1])).join("§");
ret += str.substring(pos[i], pos[i+1]);
}
ret += Array(1+str.length-pos[pos.length-1]).join("§");
document.body.innerHTML = str +"<br>"+ret;
console.log(str);
console.log(ret);
demo here

Javascript regex to match only up to 11 digits, one comma, and 2 digits after it

I have a textbox where I want only allowed up to 11 digits, an optional comma, and two more digits after it. Anything else should not be rendered when the key is pressed into the textbox:
$('#txt').keypress(function (e) {
var code = e.which;
var key = String.fromCharCode(code);
// REGEX TO AVOID CHARS & A DOT (.)
var pattern = /[a-zA-Z]|\./g;
var isMatch = pattern.test(key);
if (isMatch) {
// DO NOT RENDER CHARS & dot
e.preventDefault();
}
});
The above code works when an invalid key is pressed, such as a char or a dot, but does not ensure only one comma and only 2 digits afterwards.
This must match:
12314
123123,44
This must not:
12313,6666
Here is a demo.
UPDATE:
Any digit except numbers and comma must be avoided, so the regex I proposed is not valid since only prevents dots (.).
You should test your complete string, not only the current letter.
$('#txt').keypress(function (e) {
var key = String.fromCharCode(e.which);
var pattern=/^[0-9]{1,11}(,[0-9]{0,2})?$/;
// test this
var txt = $(this).val() + key;
if (!pattern.test(txt)) {
e.preventDefault();
}
});
​
jsfiddle example
This regex will match any string containing 1 up to 11 digits optionally followed by a , and exactly 2 more digits: ^[0-9]{1,11}(,[0-9]{2})?$
Explanation:
^ # Match the start of the string
[0-9]{1,11} # Followed by a maximum of 11 digits
(,[0-9]{2})? # Optionally followed by a comma and 2 more digits
$ # Followed by the end of the string
See it in action here.

Categories

Resources