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);
Related
The question became a bit long, but it explains the expected behaviour.
let regex = undefined;
const format = (string) => string.replace(regex, '');
format('0')
//0
format('00')
//0
format('02')
//2
format('-03')
//-3
format('023.2323')
//23.23
format('00023.2.3.2.3')
//23.23
In the above example you can see the expected results in comments.
To summarize. I'm looking for a regex not for test, for replace which formats a string:
removes 0s from the beginning if it's followed by any numbers
allows decimal digits, but just 2
allows negative numbers
allows decimal points, but just one (followed by min 1, max 2 decimal digits)
The last one is a bit difficult to handle as the user can't enter period at the same time, I'll have two formatter functions, one will be the input in the input field, and one for the closest valid value at the moment (for example '2.' will show '2.' in the input field, but the handler will receive the value '2').
If not big favour, I'd like to see explanation of the solution, why it works, and what's the purpose of which part.
Right now I'm having string.replace(/[^\d]+(\.\[^\d{1,2}])+|^0+(?!$)/g, ''), but it doesn't fulfill all the requirements.
You may use this code:
const arr = ['0', '00', '02', '-03', '023.2323', '00023.2.3.2.3', '-23.2.3.2.3']
var narr = []
// to remove leading zeroes
const re1 = /^([+-]?)0+?(?=\d)/
// to remove multiple decimals
const re2 = /^([+-]?\d*\.\d+)\.(\d+).*/
arr.forEach( el => {
el = el.replace(re1, '$1').replace(re2, '$1$2')
if (el.indexOf('.') >= 0)
el = Number(el).toFixed(2)
narr.push(el)
})
console.log(narr)
//=> ["0", "0", "2", "-3", "23.23", "23.23"]
If you aren't bound to the String#replace method, you can try this regex:
/^([+-])?0*(?=\d+$|\d+\.)(\d+)(?:\.(\d{1,2}))?$/
Inspect on regex101.com
It collects the parts of the number into capturing groups, as follows:
Sign: the sign of the number, +, - or undefined
Integer: the integer part of the number, without leading zeros
Decimal: the decimal part of the number, undefined if absent
This regex won't match if more then 2 decimal places present. To strip it instead, use this:
/^([+-])?0*(?=\d+$|\d+\.)(\d+)(?:\.(\d{1,2})\d*)?$/
Inspect on regex101.com
To format a number using one of the above, you can use something like:
let regex = /^([+-])?0*(?=\d+$|\d+\.)(\d+)(?:\.(\d{1,2}))?$/
const format = string => {
try{
const [, sign, integer, decimal = ''] = string.match(regex)
return `${(sign !== '-' ? '' : '-')}${integer}${(decimal && `.${decimal}`)}`
}catch(e){
//Invalid format, do something
return
}
}
console.log(format('0'))
//0
console.log(format('00'))
//0
console.log(format('02'))
//2
console.log(format('-03'))
//-3
console.log(format('023.23'))
//23.23
console.log(format('023.2323'))
//undefined (invalid format)
console.log(format('00023.2.3.2.3'))
//undefined (invalid format)
//Using the 2nd regex
regex = /^([+-])?0*(?=\d+$|\d+\.)(\d+)(?:\.(\d{1,2})\d*)?$/
console.log(format('0'))
//0
console.log(format('00'))
//0
console.log(format('02'))
//2
console.log(format('-03'))
//-3
console.log(format('023.23'))
//23.23
console.log(format('023.2323'))
//23.23
console.log(format('00023.2.3.2.3'))
//undefined (invalid format)
Another option is to use pattern with 3 capturing groups. In the replacement, use all 3 groups "$1$2$3"
If the string after the replacement is empty, return a single zero.
If the string is not empty, concat group 1, group 2 and group 3 where for group 3, remove all the dots except for the first one to keep it for the decimal and take the first 3 characters (which is the dot and 2 digits)
^([-+]?)0*([1-9]\d*)((?:\.\d+)*)|0+$
In parts
^ Start of string
( Capture group 1
[-+]? Match an optional + or -
) Close group
0* Match 0+ times a zero
( Capture group 2
[1-9]\d* Match a digit 1-9 followed by optional digits 0-9
) Close group
( Capture group 3
(?:\.\d+)* Repeat 0+ times matching a dot and a digit
) Close group
| Or
0+ Match 1+ times a zero
$ End of string
Regex demo
const strings = ['0', '00', '02', '-03', '023.2323', '00023.2.3.2.3', '-23.2.3.2.3', '00001234', '+0000100005.0001']
let pattern = /^([-+]?)0*([1-9]\d*)((?:\.\d+)*)|0+$/;
let format = s => {
s = s.replace(pattern, "$1$2$3");
return s === "" ? '0' : s.replace(pattern, (_, g1, g2, g3) =>
g1 + g2 + g3.replace(/(?!^)\./g, '').substring(0, 3)
);
};
strings.forEach(s => console.log(format(s)));
I need a regular expression that helps me to accept both positive and negative numbers
I have used ^-?\d*(.\d+)?$ expression
validateNegativeNumber(e: any) {
let input = String.fromCharCode(e.charCode);
const reg = /^-?\d*(.\d+)?$/;
if (!reg.test(input)) {
e.preventDefault();
}
}
Expected result: 5, +5, -5, 0
Unexpected results: 1.5, -1.5, 5++++, ++5, ---5, 5--, 50--6
You missed checking for + sign. Also there is no need for capturing groups.
Use this:
^[+-]?\d+$
An optional + or - sign at the beginning
Followed by one or more digits till the end
Demo
You can use the pattern attribute of input tag in HTML, like below:
<input pattern="^[+-]?\d+$">
Explanation: pattern attribute is available, it is better use rather than calling a function that validates the input. That will be an extra work.
I hope it helps.
Use this, for accept positive or negative both number.
^-?[0-9]\d*(\.\d+)?$
^[+-]?\d+(?:\.\d+)?$
Explanation:
^ matches the beginning of the string (so "abc212" will not validate)
[+-]? the first allowed char che be + o - matching 0 or 1 occurrence (the ?). Note that if you don't want the + sign, you can just write -?, so the regex will validate matching 0 or 1 occurrence of - as first char
\d+ after that you can have any number of digits (at least one, because we user the +)
(?:\.\d+)? at the end we can have 0 or 1 occurrence (given by the ?) of a dot (\.) followed by any number of digits (\d+). Note that the ?: at the beginning of the group says that this is a "non-capturing group")
$ matches the ending of the string (so "231aaa" will not validate)
How about this one?
const reg = /^[+-]?\d*(\.\d+)?$/;
const valids = ['+5', '-5', '5', '-5', '-0.6', '.55', '555.124'];
const invalids = ['--5', '5+', '5-'];
console.log('testing for valids array');
valids.forEach(valid => {
console.log(reg.test(valid));
});
console.log('testing for invalids array');
invalids.forEach(invalid => {
console.log(reg.test(invalid));
});
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))
})
I'm trying to achieve this regular expression check. (1 integer, 3 digits)
Valid:
0.236
0.21
1.231
1.01
Invalid:
12.23
12321
0.21323
I would like to have only 1 digit follow by a decimal with only 0-3 decimal places.
Any help would be great. I have tried this:
^(([0-9]{1})?(?=\.)[0-9]{0,3})|([0-9]{1})$
but no lock.
Edit: I should have added that I'm using a JQuery plugin called inputmask. I would like for the inputmask to only accept my requirement.
To do this with jquery-inputmask, use this
<input id="example2" data-inputmask-regex="/^\d{1}\.\d{0,3}$/" />
And then in your JavaScript file, add this
$(document).ready(function(){
$("#example2").inputmask("Regex");
});
Here is the Regex breakdown
^ - Regex must start with this expression
\d{1} - Exactly 1 digit from 0 to 9
\. - Followed by a period. Important to note that periods must be escaped
\d{0,3} - Followed by 0 to 3 digits
$ - Regex must end with this expression
I tested for all of your examples.
I would like to have only 1 whole number follow by a decimal with only 0-3 decimal places.
By "1 whole number" I take it you mean one digit, as 12 is a single whole number. If so:
\d\.\d{0,3}
That matches a single digit followed by a . followed by zero to three digits. If you want to further assert that it matches the entire string, add anchors to either end:
^\d\.\d{0,3}$
Note that the rules you've given allow for 1., which seems like you may not want. If you don't, then we need to do a bit more work:
^\d(?:\.\d{1,3})?$
That says: One digit optionally followed by a . with 1-3 digits. It has the "whole string" anchors, remove them if you don't want them.
Live Example using that last one:
var input = document.querySelector("input");
var rex = [
/\d\.\d{0,3}/,
/^\d\.\d{0,3}$/,
/^\d(?:\.\d{1,3})?$/
];
input.oninput = input.onpaste = input.onkeypress = updateDisplay;
function updateDisplay() {
rex.forEach(function(r, index) {
var display = document.getElementById("r" + index);
if (!input.value) {
display.innerHTML = "--";
} else if (input.value.match(r)) {
display.innerHTML = "valid";
} else {
display.innerHTML = "INVALID";
}
});
}
<input type="text">
<p><code>/\d\.\d{0,3}/</code> says: <span id="r0"></span></p>
<p><code>/^\d\.\d{0,3}$/</code> says: <span id="r1"></span></p>
<p><code>/^\d(?:\.\d{1,3})?$/</code> says: <span id="r2"></span></p>
I'm trying to match the first set of digits in the following examples.
some stuff (6 out of 10 as a rating)
needs to return 6
some stuff (2.3 out of 10 as a rating)
needs to return 2.3
some stuff (10 out of 10 as a rating)
needs to return 10
Also, sometimes the string won't have a number
some stuff but nothing else
var match = /\d+(\.\d+)?/.exec("some stuff (10 out of 10 as a rating)");
alert(match[0]);
\d matches any numner, 0-9
+ means 1 or more
\. matches a .
? means 0 or 1
so overall it means any number of digits (0-9) optionally followed by, a decimal point followed by 1 or more digits.
As a function:
var getFirstNumber = function(input){
var match = /\d+(\.\d+)?/.exec(input);
return match[0];
};
You can try this 'some stuff (2.3 out of 10 as a rating)'.match(/\D*(\d\.?(\d)*)/)[1]