I'm creating a form in Angular that requires the rate field to take only numbers with 2 decimal places. My HTML is as follows:
<input type="number" class="form-control" (keypress)="_keyPress($event)" (ngModelChange)="Valuechange($event,salesorder,'Rate')" [ngModelOptions]="{standalone: true}" name="customerCode" #customerCode="ngModel" [(ngModel)]="salesorder._dto.rate" [style]="{'text-align':'right'}" />
On every keypress event I'm calling _keyPress() method as follows:
_keyPress(event: any) {
const pattern = /[0-9\+\.\ ]/;
let inputChar = String.fromCharCode(event.charCode);
if (!pattern.test(inputChar)) {
// invalid character, prevent input
event.preventDefault();
}
}
The above regex works fine but does not restrict the number to 2 decimal places. I tried with various regex but could not implement the restriction to 2 decimal places. The last regex I used to do the same is as follows:
const pattern = /[0-9]+(.[0-9]{0,2})/;
I have no much idea about regex.
You can try following regex:
const pattern = /^[0-9]*\.[0-9]{2}$/
Or you may use shorthand character class \d instead of [0-9] i.e:
const pattern = /^\d*\.\d{2}$/
Description:
[0-9]{2}$ or \d{2}$ will make sure that there are exactly 2 numbers after decimal point.
You may replace * with + if there must be at least one number before point.
To restrict the decimal place to 2 digits, you could use {2}.
{0,2} means match zero, one or two times.
[0-9]+(\.[0-9]{2})
Note
This uses an unnecessary capturing group (\.[0-9]{2}) which could be written as \.[0-9]{2}
You could also use anchors to match from the beginning ^ to the end $:
^[0-9]+(\.[0-9]{2})$
or
^[0-9]+\.[0-9]{2}$
var pattern = /^[0-9]+(\.[0-9]{2})$/;
var inputs = [
"22.65",
"22.6",
"22.656"
];
for (var i = 0; i< inputs.length; i++) {
console.log(pattern.test(inputs[i]))
}
Related
Is it possible to use regex to round decimal places?
I have lines that look like this but without any spaces (space added for readability).
0, 162.3707542, -162.3707542
128.2, 151.8299471, -23.62994709 // this 151.829 should lead to 151.83
I want to remove all numbers after the second decimal position and if possible round the second decimal position based on the third position.
0, 162.37, -162.37
128.2, 151.82, -23.62 // already working .82
..., 151.83, ... // intended .83 <- this is my question
What is working
The following regex (see this sample on regex101.com) almost does what i want
([0-9]+\.)([0-9]{2})(\d{0,}) // search
$1$2 // replace
My understanding
The search works like this
group: ([0-9]+\.) find 1 up to n numbers and a point
group: ([0-9]{2}) followd by 2 numbers
group: (\d{0,}) followed by 0 or more numbers / digits
In visual-studio-code in the replacement field only group 1 and 2 are referenced $1$2.
This results in this substitution (regex101.com)
Question
Is it possible to change the last digit of $2 (group two) based on the first digit in $3 (group three) ?
My intention is to round correctly. In the sample above this would mean
151.8299471 // source
151.82 // current result
151.83 // desired result 2 was changed to 3 because of third digit 9
It is not only that you need to update the digit of $2. if the number is 199.995 you have to modify all digits of your result.
You can use the extension Regex Text Generator.
You can use a predefined set of regex's.
"regexTextGen.predefined": {
"round numbers": {
"originalTextRegex": "(-?\\d+\\.\\d+)",
"generatorRegex": "{{=N[1]:fixed(2):simplify}}"
}
}
With the same regex (-?\\d+\\.\\d+) in the VSC Find dialog select all number you want, you can use Find in Selection and Alt+Enter.
Then execute the command: Generate text based on Regular Expression.
Select the predefined option and press Enter a few times. You get a preview of the result, you can escape the UI and get back the original text.
In the process you can edit generatorRegex to change the number of decimals or to remove the simplify.
It was easier than I thought, once I found the Number.toFixed(2) method.
Using this extension I wrote, Find and Transform, make this keybinding in your keybindings.json:
{
"key": "alt+r", // whatever keybinding you want
"command": "findInCurrentFile",
"args": {
"find": "(-?[0-9]+\\.\\d{3,})", // only need the whole number as one capture group
"replace": [
"$${", // starting wrapper to indicate a js operation begins
"return $1.toFixed(2);", // $1 from the find regex
"}$$" // ending wrapper to indicate a js operation ends
],
// or simply in one line
// "replace": "$${ return $1.toFixed(2); }$$",
"isRegex": true
},
}
[The empty lines above are there just for readability.]
This could also be put into a setting, see the README, so that a command appears in the Command Palette with the title of your choice.
Also note that javascript rounds -23.62994709 to -23.63. You had -23.62 in your question, I assume -23.63 is correct.
If you do want to truncate things like 4.00 to 4 or 4.20 to 4.2 use this replace instead.
"replace": [
"$${",
"let result = $1.toFixed(2);",
"result = String(result).replace(/0+$/m, '').replace(/\\.$/m, '');",
"return result;",
"}$$"
],
We are able to round-off decimal numbers correctly using regular expressions.
We need basically this regex:
secondDD_regx = /(?<=[\d]*\.[\d]{1})[\d]/g; // roun-off digit
thirdDD_regx = /(?<=[\d]*\.[\d]{2})[\d]/g; // first discard digit
isNonZeroAfterThirdDD_regx = /(?<=[\d]*\.[\d]{3,})[1-9]/g;
isOddSecondDD_regx = /[13579]/g;
Full code (round-off digit up to two decimal places):
const uptoOneDecimalPlaces_regx = /[\+\-\d]*\.[\d]{1}/g;
const secondDD_regx = /(?<=[\d]*\.[\d]{1})[\d]/g;
const thirdDD_regx = /(?<=[\d]*\.[\d]{2})[\d]/g;
const isNonZeroAfterThirdDD_regx = /(?<=[\d]*\.[\d]{3,})[1-9]/g;
const num = '5.285';
const uptoOneDecimalPlaces = num.match(uptoOneDecimalPlaces_regx)?.[0];
const secondDD = num.match(secondDD_regx)?.[0];
const thirdDD = num.match(thirdDD_regx)?.[0];
const isNonZeroAfterThirdDD = num.match(isNonZeroAfterThirdDD_regx)?.[0];
const isOddSecondDD = /[13579]/g.test(secondDD);
// check carry
const carry = !thirdDD ? 0 : thirdDD > 5 ? 1 : thirdDD < 5 ? 0 : isNonZeroAfterThirdDD ? 1 : isOddSecondDD ? 1 : 0;
let roundOffValue;
if(/9/g.test(secondDD) && carry) {
roundOffValue = (Number(`${uptoOneDecimalPlaces}` + `${secondDD ? Number(secondDD) : 0}`) + Number(`0.0${carry}`)).toString();
} else {
roundOffValue = (uptoOneDecimalPlaces + ((secondDD ? Number(secondDD) : 0) + carry)).toString();
}
// Beaufity output : show exactly 2 decimal places if output is x.y or x
const dd = roundOffValue.match(/(?<=[\d]*[\.])[\d]*/g)?.toString().length;
roundOffValue = roundOffValue + (dd=== undefined ? '.00' : dd === 1 ? '0' : '');
console.log(roundOffValue);
For more details check: Round-Off Decimal Number properly using Regular Expression🤔
I've got my RegExp: '^[0-9]{0,6}$|^[0-9]\d{0,6}[.,]\d{0,2}'.
I need to upgrade condition above to work with an input like '000'. It should format into '0.00'
There is a list of inputs and outputs that i expect to get:
Inputs:
[5555,
55.5,
55.55,
0.50,
555555.55,
000005,
005]
Outputs:
[5555,
55.5,
55.55,
0.50,
555555.55,
0.00005,
0.05]
When working with RegExps it's important to describe, in prose, what it is you want it to match, and then what you want to do with the match.
In this case your RegExp matches a string consisting entirely of 0-6 digits, or a string starting with 1-7 digits, a . or , and then 0-2 digits.
That is: either a string with digits and no ,/., or one with digits and ,/. and as many (up to 2) digits afterwards.
You then ask to convert 000 to 0.00. I'm guessing that you want to normalize numbers to no unnecessary leading zeros, and two decimal digits.
(Now with more examples, I'm guessing that a number with a leading zero and no decimal point should have decimal point added after the first zero).
I agree that using a proper number formatter is probably the way to go, but since we are talking RegExps, here's what I'd do if I had to use RegExps:
Use capture groups, so you can easily see which part matched.
Use a regexp which doesn't capture leading zeros.
Don't try to count in RegExps. Do that in code on the side (if necessary).
Something like:
final _re = RegExp(r"^\d{0,6}$|^(\d{1,7}[,.]\d{0,2})");
String format(String number) {
var match = _re.firstMatch(number);
if (match == null) return null;
var decimals = match[1];
if (decimals != null) return decimals;
var noDecimals = match[0];
if (!noDecimals.startsWith('0')) return noDecimals;
return "0.${noDecimals.substring(1)}";
}
This matches the same strings as your RegExp.
I want to apply a mask to my phone numbers replacing some characters with "*".
The specification is the next:
Phone entry: (123) 123-1234
Output: (1**) ***-**34
I was trying with this pattern: "\B\d(?=(?:\D*\d){2})" and the replacing the matches with a "*"
But the final input is something like (123)465-7891 -> (1**)4**-7*91
Pretty similar than I want but with two extra matches. I was thinking to find a way to use the match zero or once option (??) but not sure how.
Try this Regex:
(?<!\()\d(?!\d?$)
Replace each match with *
Click for Demo
Explanation:
(?<!\() - negative lookbehind to find the position which is not immediately preceded by (
\d - matches a digit
(?!$) - negative lookahead to find the position not immediately followed by an optional digit followed by end of the line
Alternative without lookarounds :
match \((\d)\d{2}\)\s+\d{3}-\d{2}(\d{2})
replace by (\1**) ***-**\2
In my opinion you should avoid lookarounds when possible. I find them less readable, they are less portable and often less performant.
Testing Gurman's regex and mine on regex101's php engine, mine completes in 14 steps while Gurman's completes in 80 steps
Some "quickie":
function maskNumber(number){
var getNumLength = number.length;
// The number of asterisk, when added to 4 should correspond to length of the number
var asteriskLength = getNumLength - 4;
var maskNumber = number.substr(-4);
for (var i = 0; i < asteriskLength; i++) maskNumber+= '*';
var mask = maskNumber.split(''), maskLength = mask.length;
for(var i = maskLength - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var tmp = mask[i];
mask[i] = mask[j];
mask[j] = tmp;
}
return mask.join('');
}
I want to accomplish the following requirements using Regex only (no C# code can be used )
• BTN length is 12 and BTN starts with 0[123456789] then it should remove one digit from left and one digit from right.
WORKING CORRECTLY
• BTN length is 12 and it’s not the case stated above then it should always return 10 right digits by removing 2 from the start. (e.g. 491234567891 should be changed to 1234567891)
NOT WORKING CORRECTLY
• BTN length is 11 and it should remove one digit from left. WORKING CORRECTLY
for length <=10 BTNs , nothing is required to be done , they would remain as it is or Regex may get failed too on them , thats acceptable .
USING SQL this can be achieved like this
case when len(BTN) = 12 and BTN like '0[123456789]%' then SUBSTRING(BTN,2,10) else RIGHT(BTN,10) end
but how to do this using Regex .
So far I have used and able to get some result correct using this regex
[0*|\d\d]*(.{10}) but by this regex I am not able to correctly remove 1st and last character of a BTN like this 015732888810 to 1573288881 as this regex returns me this 5732888810 which is wrong
code is
string s = "111112573288881,0573288881000,057328888105,005732888810,15732888815,344956345335,004171511326,01777203102,1772576210,015732888810,494956345335";
string[] arr = s.Split(',');
foreach (string ss in arr)
{
// Match mm = Regex.Match(ss, #"\b(?:00(\d{10})|0(\d{10})\d?|(\d{10}))\b");
// Match mm = Regex.Match(ss, "0*(.{10})");
// ([0*|\\d\\d]*(.{10}))|
Match mm = Regex.Match(ss, "[0*|\\d\\d]*(.{10})");
// Match mm = Regex.Match(ss, "(?(^\\d{12}$)(.^{12}$)|(.^{10}$))");
// Match mm = Regex.Match(ss, "(info)[0*|\\d\\d]*(.{10}) (?(1)[0*|\\d\\d]*(.{10})|[0*|\\d\\d]*(.{10}))");
string m = mm.Groups[1].Value;
Console.WriteLine("Original BTN :"+ ss + "\t\tModified::" + m);
}
This should work:
(0(\d{10})0|\d\d(\d{10}))
UPDATE:
(0(\d{10})0|\d{1,2}(\d{10}))
1st alternate will match 12-digits with 0 on left and 0 on right and give you only 10 in between.
2nd alternate will match 11 or 12 digits and give you the right 10.
EDIT:
The regex matches the spec, but your code doesn't read the results correctly. Try this:
Match mm = Regex.Match(ss, "(0(\\d{10})0|\\d{1,2}(\\d{10}))");
string m = mm.Groups[2].Value;
if (string.IsNullOrEmpty(m))
m = mm.Groups[3].Value;
Groups are as follows:
index 0: returns full string
index 1: returns everything inside the outer closure
index 2: returns only what matches in the closure inside the first alternate
index 3: returns only what matches in the closure inside the second alternate
NOTE: This does not deal with anything greater than 12 digits or less than 11. Those entries will either fail or return 10 digits from somewhere. If you want results for those use this:
"(0(\\d{10})0|\\d*(\\d{10}))"
You'll get rightmost 10 digits for more than 12 digits, 10 digits for 10 digits, nothing for less than 10 digits.
EDIT:
This one should cover your additional requirements from the comments:
"^(?:0|\\d*)(\\d{10})0?$"
The (?:) makes a grouping excluded from the Groups returned.
EDIT:
This one might work:
"^(?:0?|\\d*)(\\d{10})\\d?$"
(?(^\d{12}$)(?(^0[1-9])0?(?<digit>.{10})|\d*(?<digit>.{10}))|\d*(?<digit>.{10}))
which does the exact same thing as sql query + giving result in Group[1] all the time so i didn't had to change the code a bit :)
I have a form that asks for a password and I want to validate if the password has at least eight characters, and of these eight characters at least two must be numbers and two must be letters in any order. I'm trying with this:
function validatePassword():void
{
var passVal:String = pass.text;
if(validPass(passVal))
{
trace("Password Ok");
sendForm();
}
else
{
trace("You have entered an invalid password");
}
function validPass(passVal:String):Boolean{
var pw:RegExp = /^?=.{8,}[A-Za-z]{2,}[0-9]{2,}/;
return(pw.test(passVal));
}
}
But it doesn't work. What I'm doing wrong?
Any help would be really appreciated!
use this pattern ^(?=.{8})(?=(.*\d){2})(?=(.*[A-Za-z]){2}).*$
^ anchor
(?=.{8}) look ahead for at least 8 characters
(?=(.*\d){2}) look ahead for at least 2 digits in any order
(?=(.*[A-Za-z]){2}) look ahead for at least 2 letters in any order
.*$ catch everything to the end if passed previous conditions
The problem is that your regex is forcing the numbers to follow the letters ([A-Za-z]{2,}[0-9]{2,}). While it is possible to write such a regex, I suggest using a simple length check and two regexes:
function validPass(passVal:String):Boolean{
if (passVal.length < 8)
return False;
var letterRegex:RegExp = /^.*?[A-Za-z].*?[A-Za-z].*?$/;
var numberRegex:RegExp = /^.*?\d.*?\d.*?$/;
return letterRegex.test(passVal) && numberRegex.test(passVal);
}