Dynamic Regex for Decimal Precision not Working - javascript

I have the following hard-coded RegEx expression for decimal precision & scale, which works (in another project):
// This would be a Decimal(2,3)
var regex = /\d{0,2}(\.\d{1,3})?$/;
var result = regex.test(text);
However, I don't want to hard-code multiple variations. And, interestingly, the following fails...but I don't know why.
I "think" the concatenation may (somehow) be effecting the "test"
What am I doing wrong here?
SAMPLE:
var validationRules = {
decimal: {
hasPrecision: function (precision, scale, text) {
var regex = new RegExp('\d{0,' + precision + '}(\.\d{1,' + scale + '})?$');
var result = regex.test(text);
// result is ALWAYS true ????
alert(result);
alert(regex);
}
}
};
FAILING SAMPLE-SNIPPET:
$(document).ready(function () {
var validationRules = {
decimal: {
hasPrecision: function (precision, scale, text) {
var regex = new RegExp('\d{0,' + precision + '}(\.\d{1,' + scale + '})?$');
var result = regex.test(text);
alert(result);
alert(regex);
}
}
};
var masks = {
decimal: function (e) {
// TODO: get Kendo MaskedTextBox to run RegEx
var regex = new RegExp("^([0-9\.])$");
var key = String.fromCharCode(!event.charCode ? event.which : event.charCode);
if (!regex.test(key)) {
event.preventDefault();
return false;
}
}
};
var button = $('.btn');
var textbox = $('.txt');
textbox.on('keypress', masks.decimal);
button.on('click', function () {
var text = textbox.val();
validationRules.decimal.hasPrecision(2, 3, text);
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="text" value="1111" class="txt">
<input type="button" class="btn" value="Run it">

Always look at the result when building dynamic strings. In your case you're building it and just assuming it's turning into the REGEX pattern you want.
What you're actually building is, for example:
d{0,2}(.d{1,3})?$
Why? Because REGEX patterns built via the constructor (as opposed to literals) are built as strings - and in strings \ is interpreted as an escape character.
You, however, need these back slashes to persist into your pattern, so you need to double escape. In effect, you need to escape the escape so the final one is retained.
var regex = new RegExp('\\d{0,' + precision + '}(\\.\\d{1,' + scale + '})?$');
This will result in an equivalent of your hard-coded pattern assuming precision and scale contain the intergers you think they do. Check this too. (If they contain floats, for example, this will ruin your pattern.)
As for your false positives, this is probably down to a missing start-anchor instruction, i.e. ^.
/\d{0,2}(\.\d{1,3})?$/.test("1234"); //true
/^\d{0,2}(\.\d{1,3})?$/.test("1234"); //false, note ^

please try this I have implement on my project and it's working fine
const integer = Number(4)
const decimal=Number(2)
const reg = new RegExp(^[0-9]{0,${integer }}(\\.\\d[0-9]{0,${decimal- 1}})?$)
return value && !reg.test(value) ? Maximum length for integer is ${integer} and for decimal is ${decimal} : undefined;

Related

Calculating 2 values from fields but it's not working properly

I am calculating 2 fields on a form with values but it seems in some cases it's not working. Here's my javascript. I am adding $oneTimeCostField and $recurringTotalCostField to get the value into the $totalRetailAmountField. Here's the result I am getting when I add say 1,555.00 + 566.00 = the value is 567.00 (?). Any idea what I'm doing wrong? In some cases it works correctly when the values are lower. Thanks, just stumped
var $recurringCostField = $('#am_attribute_campaign_addon_monthly_cost_value');
var $recurringTotalCostField = $('#am_attribute_campaign_addon_total_monthly_cost_value');
var $totalRetailAmountField = $('#am_oie_string_total_monthly_cost_value');
var $oneTimeCostField = $('#am_attribute_campaign_addon_one_time_cost_value');
function calcVal() {
var num1 = $oneTimeCostField.val();
var num2 = $recurringTotalCostField.val();
var result = parseFloat(num1) + parseFloat(num2);
if (!isNaN(result)) {
$totalRetailAmountField.val(result.toFixed(2));
}
}
calcVal();
$oneTimeCostField.on("keydown keyup", function() {
calcVal();
});
$recurringTotalCostField.on("keydown keyup", function() {
calcVal();
});
You need to remove the commas before parsing:
var result = parseFloat(num1.replace(/,/g, '')) + parseFloat(num2.replace(/,/g, ''));
similiar question on this link
Remove commas from the string using JavaScript
That is because parseFloat() converts the string "1,555.00" to the number 1.
To convert it to a proper floating point number, it needs to include a single dot only.
console.log(parseFloat("1.555"));

Regex to separate thousands with comma and keep two decimals

I recently came up with this code while answering another StackOverflow question. Basically, on blur, this code will properly comma separate by thousands and leave the decimal at two digits (like how USD is written [7,745.56]).
I was wondering if there is more concise way of using regex to , separate and cut off excessive decimal places. I recently updated this post with my most recent attempt. Is there a better way of doing this with regex?
Input -> Target Output
7456 -> 7,456
45345 -> 45,345
25.23523534 -> 25.23
3333.239 -> 3,333.23
234.99 -> 234.99
2300.99 -> 2,300.99
23123123123.22 -> 23,123,123,123.22
Current Regex
var result;
var str = []
reg = new RegExp(/(\d*(\d{2}\.)|\d{1,3})/, "gi");
reversed = "9515321312.2323432".split("").reverse().join("")
while (result = reg.exec(reversed)) {
str.push(result[2] ? result[2] : result[0])
}
console.log(str.join(",").split("").reverse().join("").replace(",.","."))
As an alternative to the Regex, you could use the following approach
Number(num.toFixed(2)).toLocaleString('en-US')
or
num.toLocaleString('en-US', {maximumFractionDigits: 2})
You would still have the toFixed(2), but it's quite clean. toFixed(2) though won't floor the number like you want. Same with {maximumFractionDigits: 2} as the second parameter to toLocaleString as well.
var nums = [7456, 45345, 25.23523534, 3333.239, 234.99, 2300.99, 23123123123.22]
for (var num of nums)
console.log(num, '->', Number(num.toFixed(2)).toLocaleString('en-US') )
Flooring the number like you showed is a bit tricky. Doing something like (num * 100 | 0) / 100 does not work. The calculation loses precision (e.g. .99 will become .98 in certain situations). (also |0 wouldn't work with larger numbers but even Math.floor() has the precision problem).
The solution would be to treat the numbers like strings.
function format(num) {
var num = num.toLocaleString('en-US')
var end = num.indexOf('.') < 0 ? num.length : num.indexOf('.') + 3
return num.substring(0, end)
}
var nums = [7456, 45345, 25.23523534, 3333.239, 234.99, 2300.99, 23123123123.22]
for (var num of nums) console.log(num, '->', format(num))
function format(num) {
var num = num.toLocaleString('en-US')
var end = num.indexOf('.') < 0 ? num.length : num.indexOf('.') + 3
return num.substring(0, end)
}
(when changing to another format than 'en-US' pay attention to the . in numbers as some languages use a , as fractal separator)
For Compatibility, according to CanIUse toLocaleString('en-US') is
supported in effectively all browsers (since IE6+, Firefox 2+, Chrome
1+ etc)
If you really insist on doing this purely in regex (and truncate instead of round the fractional digits), the only solution I can think of is to use a replacement function as the second argument to .replace():
('' + num).replace(
/(\d)(?=(?:\d{3})+(?:\.|$))|(\.\d\d?)\d*$/g,
function(m, s1, s2){
return s2 || (s1 + ',');
}
);
This makes all your test cases pass:
function format(num){
return ('' + num).replace(
/(\d)(?=(?:\d{3})+(?:\.|$))|(\.\d\d?)\d*$/g,
function(m, s1, s2){
return s2 || (s1 + ',');
}
);
}
test(7456, "7,456");
test(45345, "45,345");
test(25.23523534, "25.23"); //truncated, not rounded
test(3333.239, "3,333.23"); //truncated, not rounded
test(234.99, "234.99");
test(2300.99, "2,300.99");
test(23123123123.22, "23,123,123,123.22");
function test(num, expected){
var actual = format(num);
console.log(num + ' -> ' + expected + ' => ' + actual + ': ' +
(actual === expected ? 'passed' : 'failed')
);
}
I added another layer where regex that drops the unwanted decimals below hundredths on top of your regex comma adding logic;
val.replace(/(\.\d{2})\d*/, "$1").replace(/(\d)(?=(\d{3})+\b)/g, "$1,")
doIt("7456");
doIt("45345");
doIt("25.23523534");
doIt("3333.239");
doIt("234.99");
doIt("2300.99");
doIt("23123123123.22");
doIt("5812090285.2817481974897");
function doIt(val) {
console.log(val + " -> " + val.replace(/(\.\d{2})\d*/, "$1").replace(/(\d)(?=(\d{3})+\b)/g, "$1,"));
}
If multiple calls of regex replace is OK, this answer should satisfy you, since it is only has regex replace logic and nothing else.
Try:
var n = 5812090285.2817481974897;
n = n.toFixed(2).replace(/(\d)(?=(\d{3})+\.)/g, '$1,');
console.log(n);
Outputs:
5,812,090,285.28
Note: .toFixed(2) returns a string. So in order to simplify this further you must add a way to turn n into a string before executing your regex. For example:
n.toString.replace(/(\d)(?=(\d{3})+\.)/g, '$1,'); //ofc with the additional regex
Although you would think it wouldn't matter in javascript, it apparently does in this situation. So I dont know how much 'less' messy it would be to not use.
Here is a way to do it without a regular expression:
value.toLocaleString("en-US", { maximumFractionDigits: 2 })
function formatValue() {
var source = document.getElementById("source");
var output = document.getElementById("output");
var value = parseFloat(source.value);
output.innerText = value.toLocaleString("en-US", { maximumFractionDigits: 2 });
}
<input id="source" type="text" />
<button onclick="formatValue()">Format</button>
<div id="output"></div>
RegEx to rescue again!
My solution has two parts :
.toFixed : Used to limit the decimal limit
/(\d)(?=(\d\d\d)+(?!\d))/g : It makes use of back reference with three digits at a time
Here's everything put together :
// .toFixed((/\./g.test(num)) ? 2 : 0) it tests if the input number has any decimal places, if so limits it to 2 digits and if not, get's rid of it altogether by setting it to 0
num.toFixed((/\./g.test(num)) ? 2 : 0).replace(/(\d)(?=(\d\d\d)+(?!\d))/g, "$1,"))
You can see it in action here :
var input = [7456, 45345, 25.23523534, 3333.239, 234.99, 2300.99, 23123123123.22]
input.forEach(function(num) {
$('div')
.append(
$('<p>').text(num + ' => ' +
num.toFixed( (/\./g.test(num))?2:0 ).replace(/(\d)(?=(\d\d\d)+(?!\d))/g, "$1,"))
);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div> </div>
NOTE: I've only used jQuery to append the results
You can do like this
(parseFloat(num).toFixed(2)).replace(/(\d)(?=(\d{3})+(?!\d))/g, "$1,").replace(".00","")
Here just convert number to formatted number with rounded down to 2 decimal places and then remove the .00 if exist.
This can be one approach you can use.
var format = function (num) {
return (parseFloat(num).toFixed(2)).replace(/(\d)(?=(\d{3})+(?!\d))/g, "$1,").replace(".00","")
}
$(function () {
$("#principalAmtOut").blur(function (e) {
$(this).val(format($(this).val()));
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input id="principalAmtOut" type="text" />
You can use Intl.NumberFormat with style set to "decimal" and maximumFractionDigits set to 2 at options object passed at second parameter
const nums = [7456, 45345, 25.23523534, 3333.239, 234.99, 2300.99, 23123123123.22];
const formatOptions = {style:"decimal", maximumFractionDigits:2};
const formatter = new Intl.NumberFormat("en-US", formatOptions);
const formatNums = num => formatter.format(num);
let formattedNums = nums.map(formatNums);
console.log(formattedNums);
I found a solution based on #Pierre's answer without using of toFixed:
function format(n) {
n = +n;
var d = Math.round(n * 100) % 100;
return (Math.floor(n) + '').replace(/(\d)(?=(\d{3})+$)/g, '$1,') + (d > 9 ? '.' + d : d > 0 ? '.0' + d : '');
}
console.log(format(7456));
console.log(format(7456.0));
console.log(format(7456.1));
console.log(format(7456.01));
console.log(format(7456.001));
console.log(format(45345));
console.log(format(25.23523534));
console.log(format(3333.239));
console.log(format(234.99));
console.log(format(2300.99));
console.log(format(23123123123.22));
console.log(format('23123123123.22'));

Leading zeros with decimal, Javascript

I have a keypad of which inputs numbers for entering a payment.
With this i have leading zeros and would like to know the best way forward to dealing with/removing them efficiently.
JSfiddle of the keypad
The JS/JQ
$(".button_epos_e").click( function() {
btn_id = $(this).attr("id");
btn_num = btn_id.replace("pay_", "");
// alert(btn_num);
decimal = $("#number").text();
// alert(decimal);
var truenumber = decimal.replace(".", "");
// alert(truenumber);
truenumber += btn_num;
//alert(truenumber);
postDecimal = truenumber.slice(-2);
// alert(postDecimal);
preDecimal = truenumber.replace(postDecimal, "");
preDecInt = parseInt(preDecimal);
// alert(preDecimal);
newDecimal = preDecimal+"."+postDecimal;
$("#number").html(newDecimal);
});
There's quite a bit of things that should be changed. But this should suffice for your needs:
preDecimal = +truenumber.slice(0, -2) + "";
The +truenumber.slice(0, -2) part converts the string to a number, deleting unnecessary leading zeros, and adding an empty string converts it back to a string (which isn't really necessary, though).

Adding User input without rounding (Google Apps Script)

I am adding a users input in to UI as they add numbers and returning the results. The input is currency so I need to carry it out two decimals and not round.
Here is an example of my code:
function ceiling2(number) {
var ceiling2;
return ceiling2 = Math.ceil(number*100)/100;
}
//Totals
function lD23Total (e){
var app = UiApp.getActiveApplication();
var tB1v = parseInt(e.parameter.TextBox1);
var tB9v = parseInt(e.parameter.TextBox9);
var tB17v = parseInt(e.parameter.TextBox17);
var tB25v = parseInt(e.parameter.TextBox25);
var tB33v = parseInt(e.parameter.TextBox33);
var tB41v = parseInt(e.parameter.TextBox41);
var tB49v = parseInt(e.parameter.TextBox49);
var lD23 = app.getElementById("LabelD23").setStyleAttribute('fontWeight','bold');
var lD23T = tB1v + tB9v + tB17v + tB25v + tB33v + tB41v + tB49v;
lD23.setText("$ " + ceiling2(lD23T));
var app = UiApp.getActiveApplication();
app.close();
return app;
}
Currently it returns a rounded number.
I appreciate an suggestions you may offer!
Jon
The function parseInt() will convert the value to an integer, dropping the values after the decimal. Use parseFloat() instead.
I think your function is just fine...
if you remove the parseInt() and replace it either with parseFloat()as suggested by Eric or by Number() it should work...
if not then the problem might come from the way numbers are written:
If you used 26,4567 but you should use 26.4567 with a dot as separator in place of a comma.
Could you try and keep us informed ?
regards,
Serge
Or you can use this before sending to your function:
var newnumber=Number(number.toString().replace(",","."));// convert to string, replace comma with dot and set as number again.
and your function will work in both cases

Convert JavaScript String to be all lowercase

How can I convert a JavaScript string value to be in all lowercase letters?
Example: "Your Name" to "your name"
var lowerCaseName = "Your Name".toLowerCase();
Use either toLowerCase or toLocaleLowerCase methods of the String object. The difference is that toLocaleLowerCase will take current locale of the user/host into account. As per § 15.5.4.17 of the ECMAScript Language Specification (ECMA-262), toLocaleLowerCase…
…works exactly the same as toLowerCase
except that its result is intended to
yield the correct result for the host
environment’s current locale, rather
than a locale-independent result.
There will only be a difference in the
few cases (such as Turkish) where the
rules for that language conflict with
the regular Unicode case mappings.
Example:
var lower = 'Your Name'.toLowerCase();
Also note that the toLowerCase and toLocaleLowerCase functions are implemented to work generically on any value type. Therefore you can invoke these functions even on non-String objects. Doing so will imply automatic conversion to a string value prior to changing the case of each character in the resulting string value. For example, you can apply toLowerCase directly on a date like this:
var lower = String.prototype.toLowerCase.apply(new Date());
and which is effectively equivalent to:
var lower = new Date().toString().toLowerCase();
The second form is generally preferred for its simplicity and readability. On earlier versions of IE, the first had the benefit that it could work with a null value. The result of applying toLowerCase or toLocaleLowerCase on null would yield null (and not an error condition).
Yes, any string in JavaScript has a toLowerCase() method that will return a new string that is the old string in all lowercase. The old string will remain unchanged.
So, you can do something like:
"Foo".toLowerCase();
document.getElementById('myField').value.toLowerCase();
toLocaleUpperCase() or lower case functions don't behave like they should do. For example, on my system, with Safari 4, Chrome 4 Beta, and Firefox 3.5.x, it converts strings with Turkish characters incorrectly. The browsers respond to navigator.language as "en-US", "tr", "en-US" respectively.
But there isn't any way to get user's Accept-Lang setting in the browser as far as I could find.
Only Chrome gives me trouble although I have configured every browser as tr-TR locale preferred. I think these settings only affect the HTTP header, but we can't access to these settings via JavaScript.
In the Mozilla documentation it says "The characters within a string are converted to ... while respecting the current locale. For most languages, this will return the same as ...". I think it's valid for Turkish, and it doesn't differ if it's configured as en or tr.
In Turkish it should convert "DİNÇ" to "dinç" and "DINÇ" to "dınç" or vice-versa.
Just an example for toLowerCase(), toUpperCase() and a prototype for the not yet available toTitleCase() or toProperCase():
String.prototype.toTitleCase = function() {
return this.split(' ').map(i => i[0].toUpperCase() + i.substring(1).toLowerCase()).join(' ');
}
String.prototype.toPropperCase = function() {
return this.toTitleCase();
}
var OriginalCase = 'Your Name';
var lowercase = OriginalCase.toLowerCase();
var upperCase = lowercase.toUpperCase();
var titleCase = upperCase.toTitleCase();
console.log('Original: ' + OriginalCase);
console.log('toLowerCase(): ' + lowercase);
console.log('toUpperCase(): ' + upperCase);
console.log('toTitleCase(): ' + titleCase);
I paid attention that lots of people are looking for strtolower() in JavaScript. They are expecting the same function name as in other languages, and that's why this post is here.
I would recommend using a native JavaScript function:
"SomE StriNg".toLowerCase()
Here's the function that behaves exactly the same as PHP's one (for those who are porting PHP code into JavaScript)
function strToLower (str) {
return String(str).toLowerCase();
}
Methods or functions: toLowerCase() and toUpperCase()
Description: These methods are used to cover a string or alphabet from lowercase to uppercase or vice versa. E.g., "and" to "AND".
Converting to uppercase:
Example code:
<script language=javascript>
var ss = " testing case conversion method ";
var result = ss.toUpperCase();
document.write(result);
</script>
Result: TESTING CASE CONVERSION METHOD
Converting to lowercase:
Example Code:
<script language=javascript>
var ss = " TESTING LOWERCASE CONVERT FUNCTION ";
var result = ss.toLowerCase();
document.write(result);
</script>
Result: testing lowercase convert function
Explanation: In the above examples,
toUpperCase() method converts any string to "UPPER" case letters.
toLowerCase() method converts any string to "lower" case letters.
Note that the function will only work on string objects.
For instance, I was consuming a plugin, and was confused why I was getting a "extension.tolowercase is not a function" JavaScript error.
onChange: function(file, extension)
{
alert("extension.toLowerCase()=>" + extension.toLowerCase() + "<=");
Which produced the error "extension.toLowerCase is not a function". So I tried this piece of code, which revealed the problem!
alert("(typeof extension)=>" + (typeof extension) + "<=");;
The output was "(typeof extension)=>object<=" - so aha, I was not getting a string var for my input. The fix is straightforward though - just force the darn thing into a String!:
var extension = String(extension);
After the cast, the extension.toLowerCase() function worked fine.
Option 1: Using toLowerCase()
var x = 'ABC';
x = x.toLowerCase();
Option 2: Using your own function
function convertToLowerCase(str) {
var result = '';
for (var i = 0; i < str.length; i++) {
var code = str.charCodeAt(i);
if (code > 64 && code < 91) {
result += String.fromCharCode(code + 32);
} else {
result += str.charAt(i);
}
}
return result;
}
Call it as:
x = convertToLowerCase(x);
Simply use JS toLowerCase()
let v = "Your Name"
let u = v.toLowerCase(); or
let u = "Your Name".toLowerCase();
const str = 'Your Name';
// convert string to lowercase
const lowerStr = str.toLowerCase();
// print the new string
console.log(lowerStr);
In case you want to build it yourself:
function toLowerCase(string) {
let lowerCaseString = "";
for (let i = 0; i < string.length; i++) {
// Find ASCII charcode
let charcode = string.charCodeAt(i);
// If uppercase
if (charcode > 64 && charcode < 97) {
// Convert to lowercase
charcode = charcode + 32
}
// Back to char
let lowercase = String.fromCharCode(charcode);
// Append
lowerCaseString = lowerCaseString.concat(lowercase);
}
return lowerCaseString
}
You can use the in built .toLowerCase() method on JavaScript strings. Example:
var x = "Hello";
x.toLowerCase();
Try this short way:
var lower = (str+"").toLowerCase();
Try
<input type="text" style="text-transform: uppercase"> <!-- uppercase -->
<input type="text" style="text-transform: lowercase"> <!-- lowercase -->
Demo - JSFiddle

Categories

Resources