How to fetch only numbers which are not starting with 2 using regex in javascript? - javascript

I have a list of numbers like the following one:
200
302
301
201
205
500
Using regex, how can I fetch only the numbers which don't start with 2?
So the output should looks like :
302
301
500

Brief
There are multiple ways to accomplish this (presented below).
Note: I know the patterns only match the first character. Please read the entire answer to understand why (and how to match the full number if that's needed).
Code
The Usage section uses the first regex from each method (as it's a simple validation on the first character). The second regex from each method allows you to capture the entire number if that's the intention.
Method 1 - Regex: Character set
This method takes 39 steps and is 9 (+3) characters long.
See regex in use here
\b[013-9]
\b[013-9]\d*
Method 2 - Regex: Negative lookahead
This method takes 63 steps and is 9 (+1) characters long.
See regex in use here
\b(?!2)\d
\b(?!2)\d*
Method 3 - Regex: Negated character set
This method takes 39 steps and is 8 (+3) characters long.
See regex in use here
\b[^\D2]
\b[^\D2]\d*
Method 4 - JavaScript: startsWith
startsWith("2");
Method 5 - JavaScript: Array element
Assuming n is the number converted to a string.
n[0] !== "2"
Method 6 - JavaScript: Math
Assuming n is a positive number (we make it positive for the validation).
while(n >= 10) {
n = Math.floor(n/10);
}
if(n !== 2)
Usage
var nums = [200,302,301,201,205,500];
console.log("Method 1");
var r = /\b[013-9]/g
nums.forEach(function(s){
s = s.toString();
if(s.match(r)) {
console.log(s);
}
});
console.log("\nMethod 2");
var r = /\b(?!2)\d/g
nums.forEach(function(s){
s = s.toString();
if(s.match(r)) {
console.log(s);
}
});
console.log("\nMethod 3");
var r = /\b[^\D2]/g
nums.forEach(function(s){
s = s.toString();
if(s.match(r)) {
console.log(s);
}
});
console.log("\nMethod 4");
nums.forEach(function(s){
s = s.toString();
if(!s.startsWith("2")) {
console.log(s);
}
});
console.log("\nMethod 5");
nums.forEach(function(s){
s = s.toString();
if(s[0] !== "2") {
console.log(s);
}
});
console.log("\nMethod 6");
nums.forEach(function(s){
var n = Math.abs(s);
while(n >= 10) {
n = Math.floor(n/10);
}
if(n !== 2) {
console.log(s);
}
});
Results
Input
200
302
301
201
205
500
Output
302
301
500
Explanation
Note: All the regular expressions in my answer use \b (word boundary) to ensure the start of the number. You can replace this with your needs. If the input is multiline, for example, you may want to use ^ (start of line assertion) with the multiline flag (typically m). The below explanations exclude the explanation of the \b token (since I've already explained it).
Method 1 - Regex: Character set
[013-9] Match a character in the set (0, 1, or a number in the range of 3-9)
Method 2 - Regex: Negative lookahead
(?!2)\d Negative lookahead ensuring what follows is not a 2.
Method 3 - Regex: Negated character set
[^\D2] Match any character not in the set (any non-digit or 2). Note that [^\D2] is actually a double negative that means match any digit, excluding 2
Method 4 - JavaScript: startsWith
From Mozilla's documentation:
Syntax
str.startsWith(searchString[, position])
Parameters
searchString
The characters to be searched for at the start of this string.
position Optional
The position in this string at which to begin searching for searchString; defaults to 0.
Return value
true if the given characters are found at the beginning of the
string; otherwise, false.
Description
This method lets you determine whether or not a string begins with
another string. This method is case-sensitive.
Method 5 - JavaScript: Array element
This method is simply taking the first digit in a number and testing it against the string 2 to see if they match. Anything that returns false is returned (does not start with 2).
Method 6 - JavaScript: Math
This method gets the absolute value of a number Math.abs() and then continuously divides the number by 10 while removing decimal places (Math.floor(n/10)) until the number is less than 10. The result is then checked against the number 2 to ensure it doesn't match if(n !== 2).

Related

Javascript regex for money with max length

I want validate a money string with numbers max length 13 with 2 decimal. I have a comma as decimal separator and a period as a thousands separator.
I have this regex:
/^(\d{1}\.)?(\d+\.?)+(,\d{2})?$/
For sintax is valid but not for max length. What I need to add to this regex?
For example, these strings must be valid:
1.000.000.000.000
1.000.000.000.000,00
1
1,00
123,45
And these must be invalid:
10.000.000.000.000
10.000.000.000.000,00
10.000.000.000.000.000
10.000.000.000.000.000,00
Maybe try to assert position is not followed by 18 digits/dots using a negative lookahead:
^(?![\d.]{18})\d{1,3}(?:\.\d{3})*(?:,\d\d?)?$
See an online demo. Here is assumed you would also allow a single digit decimal.
^ - Open line anchor.
(?![\d.]{18}) - Negative lookahead to prevent 18 digits/dots ahead.
\d{1,3} - One-to-three digits.
(?:\.\d{3})* - A non-capture group of a literal dot followed by three digits with a 0+ multiplier.
(?:,\d\d?)? - Optional non-capture group of a comma followed by either 1 or two digits. Remove the question mark to make the 2nd decimal non-optional.
$ - End line anchor.
You may use this regex for validation:
^(?=[\d.]{1,17}(?:,\d{2})?$)\d{1,3}(?:\.\d{3})*(?:,\d{2})?$
RegEx Demo
RegEx Details:
^: Start
(?=[\d.]{1,17}(?:,\d{2})?$): Lookahead to match dot or digit 1 to 17 times followed by optional comma and 2 digits
\d{1,3}: Match 1 to 3 digits
(?:\.\d{3})*: Match . followed by 3 digits. Repeat this group 0 or more times
(?:,\d{2})?: Match optional , followed 2 decimal digits
$: End
90% of the time there is a better solution than using regex. It's probably best just to convert your strings into a real number then compare vs. your limit (ie 9999999999999.99).
// Pass a string
function convertStr(string) {
/*
Remove all '.'
Replace all ',' with '.'
*/
let numStr = string.split('.').join('').replaceAll(',', '.');
// Convert modified string into a real number
let realNum = parseFloat(numStr);
/*
if converted string is a real number...
round it to two decimal places and return it
Otherwise return false
*/
return !Number.isNaN(realNum) ? Math.round((realNum + Number.EPSILON) * 100) / 100 : false;
}
// Pass a string and the maxed number
function numLimit(string, limit) {
// Get the result of convertString()
let number = convertStr(string);
// if the result is equal to or less than limit...
if (number <= limit) {
return true;
} else {
return false;
}
}
const limit = 9999999999999.99;
const valid = ['1.000.000.000.000',
'1.000.000.000.000,00', '1', '1,00', '123,45'
];
const invalid = ['10.000.000.000.000', '10.000.000.000.000,00', '10.000.000.000.000.000', '10.000.000.000.000.000,00'];
let validResults = valid.map(str => numLimit(str, limit));
let invalidResults = invalid.map(str => numLimit(str, limit));
console.log('valid: ' + validResults);
console.log('invalid: ' + invalidResults);

Regex for getting only the last N numbers in javascript

I've being trying to generate a regex for this string:
case1: test-123456789 should get 56789
case2: test-1234-123456789 should get 56789
case3: test-12345 should fail or not giving anything
what I need is a way to get only the last 5 numbers from only 9 numbers
so far I did this:
case.match(/\d{5}$/)
it works for the first 2 cases but not for the last one
You may use
/\b\d{4}(\d{5})$/
See the regex demo. Get Group 1 value.
Details
\b - word boundary (to make sure the digit chunks are 9 digit long) - if your digit chunks at the end of the string can contain more, remove \b
\d{4} - four digits
(\d{5}) - Group 1: five digits
$ - end of string.
JS demo:
var strs = ['test-123456789','test-1234-123456789','test-12345'];
var rx = /\b\d{4}(\d{5})$/;
for (var s of strs) {
var m = s.match(rx);
if (m) {
console.log(s, "=>", m[1]);
} else {
console.log("Fail for ", s);
}
}
You can try this:
var test="test-123456789";
console.log((test.match(/[^\d]\d{4}(\d{5})$/)||{1: null/*default value if not found*/})[1]);
This way supports default value for when not found any matching (look at inserted comment inline above code.).
You can use a positive lookbehind (?<= ) to assert that your group of 5 digits is preceeded by a group of 4 digits without including them in the result.
/(?<=\d{4})\d{5}$/
var inputs = [
"test-123456789", // 56789
"test-1234-123456789", // 56789
"test-12345", //fail or not giving anything
]
var rgx = /(?<=\d{4})\d{5}$/
inputs.forEach(str => {
console.log(rgx.exec(str))
})

How to match only those numbers which have an even number of `%`s preceding them?

I want to catch numbers appearing anywhere in a string, and replace them with "(.+)".
But I want to catch only those numbers which have an even number of %s preceding them. No worries if any surrounding chars get caught up: we can use capture groups to filter out the numbers.
I'm unable to come up with an ECMAscript regular expression.
Here is the playground:
abcd %1 %%2 %%%3 %%%%4 efgh
abcd%12%%34%%%666%%%%11efgh
A successful catch will behave like this:
Things I have tried:
If you have realised, the third attempt is almost working. The only problems are in the second line of playground.
Actually, what I wanted to say in that expression is:
Match a number if it is preceded by an even number of %s AND either of the following is true:
The above whole expression is preceded by nothing [absence of (unconsumed or otherwise) character].
The above whole expression is preceded by a character other than %.
Is there a way to match the absence of a character?
That's what I was trying to do by using \0 in the third attempt.
You can use (?:[^%\d]|^|\b(?=%))(?:%%)*(\d+) as a pattern, where your number is stored into the first capturing group. This also treats numbers preceded by zero %-characters.
This will match the even number of %-signs, if they are preceded by:
neither % nor number (so we don't need to catch the last number before a %, as this wouldn't work with chains like %%1%%2)
the start of the string
a word boundary (thus any word character), for the chains mentioned above
You can see it in action here
Issue
You want a regex with a negative infinite-width lookbehind:
(?<=(^|[^%])(?:%%)*)\d+
Here is the .NET regex demo
In ES7, it is not supported, you need to use language-specific means and a simplified regex to match any number of % before a digit sequence: /(%*)(\d+)/g and then check inside the replace callback if the number of percentage signs is even or not and proceed accordingly.
JavaScript
Instead of trying to emulate a variable-width lookbehind, you may just use JS means:
var re = /(%*)(\d+)/g; // Capture into Group 1 zero or more percentage signs
var str = 'abcd %1 %%2 %%%3 %%%%4 efgh<br/><br/>abcd%12%%34%%%666%%%%11efgh';
var res = str.replace(re, function(m, g1, g2) { // Use a callback inside replace
return (g1.length % 2 === 0) ? g1 + '(.+)' : m; // If the length of the %s is even
}); // Return Group 1 + (.+), else return the whole match
document.body.innerHTML = res;
If there must be at least 2 % before digits, use /(%+)(\d+)/g regex pattern where %+ matches at least 1 (or more) percentage signs.
Conversion to C++
The same algorithm can be used in C++. The only problem is that there is no built-in support for a callback method inside the std::regex_replace. It can be added manually, and used like this:
#include <iostream>
#include <cstdlib>
#include <string>
#include <regex>
using namespace std;
template<class BidirIt, class Traits, class CharT, class UnaryFunction>
std::basic_string<CharT> regex_replace(BidirIt first, BidirIt last,
const std::basic_regex<CharT,Traits>& re, UnaryFunction f)
{
std::basic_string<CharT> s;
typename std::match_results<BidirIt>::difference_type
positionOfLastMatch = 0;
auto endOfLastMatch = first;
auto callback = [&](const std::match_results<BidirIt>& match)
{
auto positionOfThisMatch = match.position(0);
auto diff = positionOfThisMatch - positionOfLastMatch;
auto startOfThisMatch = endOfLastMatch;
std::advance(startOfThisMatch, diff);
s.append(endOfLastMatch, startOfThisMatch);
s.append(f(match));
auto lengthOfMatch = match.length(0);
positionOfLastMatch = positionOfThisMatch + lengthOfMatch;
endOfLastMatch = startOfThisMatch;
std::advance(endOfLastMatch, lengthOfMatch);
};
std::sregex_iterator begin(first, last, re), end;
std::for_each(begin, end, callback);
s.append(endOfLastMatch, last);
return s;
}
template<class Traits, class CharT, class UnaryFunction>
std::string regex_replace(const std::string& s,
const std::basic_regex<CharT,Traits>& re, UnaryFunction f)
{
return regex_replace(s.cbegin(), s.cend(), re, f);
}
std::string my_callback(const std::smatch& m) {
if (m.str(1).length() % 2 == 0) {
return m.str(1) + "(.+)";
} else {
return m.str(0);
}
}
int main() {
std::string s = "abcd %1 %%2 %%%3 %%%%4 efgh\n\nabcd%12%%34%%%666%%%%11efgh";
cout << regex_replace(s, regex("(%*)(\\d+)"), my_callback) << endl;
return 0;
}
See the IDEONE demo.
Special thanks for the callback code goes to John Martin.
I don't know ECMAScript but following documentation has the answer:
ECMAScript regex
Search for negative lookahead, which will result in something like this:
(?!%)(([%]{2})*\d+)
...where (?!%) means not preceded by % literal.

javascript regular expression test for 6 digit numbers only. comma seperated

and so this must pass:
454555, 939999 , 019999 ,727663
its for a user entering 6 digit invoice numbers. it should fail if a number is 5 or 7 digit and not 6. so 1234567, 123456 should fail, as one set is more than 6 numbers.
So far I have :
[0-9]{6}(\s*,*,\s*[0-9]{6})*
which only draw back is that it accepts 7 or more digit numbers. cant figure out if its even possible at this point to do both, test for 6 digits separated by a comma and one or more space, and all the digits have to be only 6 digits and fail if one is not.
any help appreciated. regular expressions are not my forte.
thanks
Norman
You can write it using regex like the function below.
const isPassword = (password: string) => /^\d{6}$/gm.test(password);
And here is an example test file below.
test('should recognize a valid password', () => {
expect(isPassword('123456')).toBe(true);
expect(isPassword('000000')).toBe(true);
});
test('should recognize an invalid password', () => {
expect(isPassword('asdasda1234')).toBe(false);
expect(isPassword('1234567')).toBe(false);
expect(isPassword('a123456a')).toBe(false);
expect(isPassword('11.11.11')).toBe(false);
expect(isPassword('aaaaaa')).toBe(false);
expect(isPassword('eeeeee')).toBe(false);
expect(isPassword('......')).toBe(false);
expect(isPassword('werwerwerwr')).toBe(false);
});
In order to validate the full string you can use this regex.
^(\s*\d{6}\s*)(,\s*\d{6}\s*)*,?\s*$
It works with six digits only, and you have to enter at least one 6 digit number.
It also works if you have a trailing comma with whitespaces.
It's accepting more than six digit numbers because you're not anchoring the text, and for some odd reason you're optionally repeating the comma. Try something like this:
^[0-9]{6}(?:\s*,\s*[0-9]{6})*$
Also note that [0-9] is equivalent to \d, so this can be rewritten more concisely as:
^\d{6}(?:\s*,\s*\d{6})*$
Your regex does not match 7 digits in a row, but it also doesn't enforce that it matches the whole string. It just has to match some substring in the string, so it would also match each of these:
"1234512345612345612345"
"NaNaNaN 123456, 123456 BOOO!"
"!##$%^&*({123456})*&^%$##!"
Just add the start of string (^) and end of string ($) anchors to enforce that the whole string matches and it will work correctly:
^[0-9]{6}(\s*,*,\s*[0-9]{6})*$
Also note that ,*, could be shortened to ,+, and if you only want one comma in a row, just use ,, not ,* or ,+.
You can also replace [0-9] with \d:
^\d{6}(\s*,\s*\d{6})*$
Using only regex:
var commaSeparatedSixDigits = /^(?:\d{6}\s*,\s*)*\d{6}$/;
if (myInput.test(commaSeparatedSixDigits)) console.log( "Is good!" );
This says:
^ - Starting at the beginning of the string
(?:…)* - Find zero or more of the following:
\d{6} - six digits
\s* - maybe some whitespace
, - a literal comma
\s* - maybe some whitespace
\d{6} - Followed by six digits
$ - Followed by the end of the string
Alternatively:
var commaSeparatedSixDigits = /^\s*\d{6}(?:\s*,\s*\d{6})*\s*$/;
I leave it as an exercise to you to decipher what's different about this.
Using JavaScript + regex:
function isOnlyCommaSeparatedSixDigitNumbers( str ){
var parts = srt.split(/\s*,\s*/);
for (var i=parts.length;i--;){
// Ensure that each part is exactly six digit characters
if (! /^\d{6}$/.test(parts[i])) return false;
}
return true;
}
I see a lot of complication here. Sounds to me like what you want is pretty simple:
/^(\d{6},)*\d{6}$/
Then we account for whitespace:
/^\s*(\d{6}\s*,\s*)*\d{6}\s*$/
But as others have noted, this is actually quite simple in JavaScript without using regex:
function check(input) {
var parts = input.split(',');
for (var i = 0, n = parts.length; i < n; i++) {
if (isNaN(+parts[i].trim())) {
return false;
}
}
return true;
}
Tested in the Chrome JavaScript console.
There isn;t any real need for a regexp. Limit the input to only 6 characters, only accept numbers and ensure that the input has 6 digits (not show here). So you would need:
HTML
<input type='text' name='invoice' size='10' maxlength='6' value='' onkeypress='evNumersOnly(event);'>
JavaScript
<script>
function evNumbersOnly( evt ) {
//--- only accepts numbers
//--- this handles incompatabilities between browsers
var theEvent = evt || window.event;
//--- this handles incompatabilities between browsers
var key = theEvent.keyCode || theEvent.which;
//--- convert key number to a letter
key = String.fromCharCode( key );
var regex = /[0-9]/; // Allowable characters 0-9.+-,
if( !regex.test(key) ) {
theEvent.returnValue = false;
//--- this prevents the character from being displayed
if(theEvent.preventDefault) theEvent.preventDefault();
}
}
</script>

Why this match fail?

I have this code :
var tlTemp=new Array();
tlTemp.push("00 - 01:??:?? - TL 1");
tlTemp.push("00 - 12:??:?? - TL 2");
for(i=0; i<tlTemp.length; i++) {
var removedTL = tlTemp[i].match(/^(\d\d) - (\?\?|10|0\d):(\?\?|[0-5]\d):(\?\?|[0-5]\d) - (.*)/);
if(removedTL!=null) {
alert("ok");
}
else
{
alert("no");
return;
}
}
and I don't understand why first string print ok and the second (so similar) no. Why?
The appropriate part of the regexp that defines the different part of the string is:
(\?\?|10|0\d)
It matches:
??
10
0x where x is a digit
So 12 does not match.
Now, also there is TL 2 instead of TL 1 but in the regexp this is defined as:
(.*)
which matches everything so that is not causing the problem.
Because your regular expression explicitly excludes it.
This section:
/^(\d\d) - (\?\?|10|0\d)
constrains matches to strings starting with two digits, a space, a dash, and a space, and then either "??", "10", or "0" followed by a digit.
This part of your regular expression: (\?\?|10|0\d) should be changed to (\?\?|10|\d\d). The zero is changed to a \d. in the first string, that part of the string is 01, while the second string has 12, not matching the regular expression.

Categories

Resources