Javascript to test value against regex and later value if needed - javascript

in my webpage I have a total in currency format that can either be positive or negative.
Example $5.50 or $(5.50).
This value is nothing other than text contained within a span tag. I'm trying to read the value and convert it into a numeric value in js where I can then perform math calculations against it.
Example $5.50 -> 5.50 and $(5.50) -> -5.50
I have written the following regex script to handle converting negative currency values into numeric values
var regex = /^\$*?\((\d+(\.)?(\d+)?)\)$/
I have the following methods to handle retrieving and converting the value.
//retrieve value from template
$.fn.fieldVal = function () {
var val;
if ($(this).is(':input')) {
val = $(this).val();
} else {
val = $(this).text();
}
return convertCurrencyToNumeric(val);
};
//convert currency to numeric value
function convertCurrencyToNumeric(n) {
var regex = /^\$*?\((\d+(\.)?(\d+)?)\)$/
n = n.replace(/[^0-9-\.]/g, '');
if(isNumber(n)) {
n = parseFloat(n);
return n;
}
return 0;
}
//test if numeric
function isNumber(n) {
return !isNaN(parseFloat(n)) && isFinite(n);
}
I'm not clear how to first test if the value is negative and secondly if negative, replace the value with regex outcome.

Note: Negating classes can really clear up regEx problems, IMO. And no, I don't care what JSLint's opinion on the matter is. Using '.' is slow and clumsy and the rationale given for that particular lint gotcha is absurd.
function convertCurrency(str){
var negMatch = ( str.match(/(^\$-|^-\$|^$\()/g) ), //handles -$5.05 or $-5.05 too
str = str.replace(/[^\d.]/g,''), //anything that's not a digit or decimal point
//gotcha, Europeans use ',' as a decimal point so there's a localization concern
num = parseFloat(str);
if(negMatch){ num *= -1; }
return num;
}

function getMoney (str) {
var amount = str.replace(/(\$)(\()?(\d+\.\d{0,2})\)?/,
function (match, dollar, neg, money) {
var negSign = neg ? "-" : "";
return negSign + money;
}
);
return parseFloat(amount);
}
var str1 = "$(5.50)";
var str2 = "$5.50";
console.log( getMoney(str1) );
console.log( getMoney(str2) );

Related

Function that pads with zeros an input number

i'm having a serious issue here. I have a function that pads a user's input with zeros. For example if i enter 88 it will normalize it to:
00000088. My function is this:
export default length => (value) => {
const noLeadingZeros = value.toString().replace(/(0+)/, '');
if (noLeadingZeros.length === 0) {
return value;
}
return padLeft(noLeadingZeros, length);
};
with padleft is:
export default (num, len) => (
len > num.toString().length ? '0'.repeat(len - num.toString().length) + num
: num
);
My problem is that if i entered something like this:
80112345 it convert it to 08112345. Any ideas?
Using slice:
let str = '00000000' + 88;
let resp = str.slice(-8, str.length)
console.log(resp) // 00000088
In your replace, you're replacing all the zeros in the number not just those on the left side, and even if there are zeros on the left side, why remove them if you're just going to add them back. You could use a for loop that pads the string with a zero n times (where n is the number of digits that the string needs to have length 8), or (thanks to a comment by #AndrewBone), you can use the .repeat() function that does this for you:
function padLeft(value, len) {
return '0'.repeat(String(value).length < len ? len - String(value).length : 0) + value;
}
console.log(padLeft("", 8));
console.log(padLeft("88", 8));
console.log(padLeft("00088", 8));
console.log(padLeft("12312388", 8));
console.log(padLeft("00000000", 8));
this looks wrong :
const noLeadingZeros = value.toString().replace(/(0+)/, '');
you are deleting every zeros out of your number... even those inside !
You can use this regex instead, instead of for /(0+)/ in your code :
/\b(0+)/
explanation : the \b ensures the zeros are at the beginning of a word
or this
/^(0+)/
explanation : the ^ ensure this is the beginning of the string
Just use a RegEx to assert that the number is a valid number.
/0+/
Then get the number of digits in the number:
('' + num).length;
Then put the whole thing together
var paddedNum ='';
for (var i=0;i<8-len;i++) {
paddedNum += "0";
}
paddedNum += num;

How do get input 2^3 to Math.pow(2, 3)?

I have this simple calculator script, but it doesn't allow power ^.
function getValues() {
var input = document.getElementById('value').value;
document.getElementById('result').innerHTML = eval(input);
}
<label for="value">Enter: </label><input id="value">
<div id="result">Results</div>
<button onclick="getValues()">Get Results</button>
I tried using input = input.replace( '^', 'Math.pow(,)');
But I do not know how to get the values before '^' and after into the brackets.
Example: (1+2)^3^3 should give 7,625,597,484,987
Use a regular expression with capture groups:
input = '3 + 2 ^3';
input = input.replace(/(\d+)\s*\^\s*(\d+)/g, 'Math.pow($1, $2)');
console.log(input);
This will only work when the arguments are just numbers. It won't work with sub-expressions or when you repeat it, like
(1+2)^3^3
This will require writing a recursive-descent parser, and that's far more work than I'm willing to put into an answer here. Get a textbook on compiler design to learn how to do this.
I don't think you'll be able to do this with simple replace.
If you want to parse infix operators, you build two stacks, one for symbols, other for numbers. Then sequentially walk the formula ignoring everything else than symbols, numbers and closing parenthesis. Put symbols and numbers into their stacks, but when you encounter closing paren, take last symbol and apply it to two last numbers. (was invented by Dijkstra, I think)
const formula = '(1+2)^3^3'
const symbols = []
const numbers = []
function apply(n2, n1, s) {
if (s === '^') {
return Math.pow(parseInt(n1, 10), parseInt(n2, 10))
}
return eval(`${n1} ${s} ${n2}`)
}
const applyLast = () => apply(numbers.pop(), numbers.pop(), symbols.pop())
const tokenize = formula => formula.split(/(\d+)|([\^\/\)\(+\-\*])/).filter(t => t !== undefined && t !== '')
const solver = (formula) => {
const tf = tokenize(formula)
for (let l of formula) {
const parsedL = parseInt(l, 10)
if (isNaN(parsedL)) {
if (l === ')') {
numbers.push(applyLast())
continue
} else {
if (~['+', '-', '*', '/', '^'].indexOf(l))
symbols.push(l)
continue
}
}
numbers.push(l)
}
while (symbols.length > 0)
numbers.push(applyLast())
return numbers.pop()
}
console.log(solver(formula))
Get your input into a string and do...
var input = document.getElementById('value').value;
var values = input.split('^'); //will save an array with [value1, value 2]
var result = Math.pow(values[0], values[1]);
console.log(result);
This only if your only operation is a '^'
EDIT: Saw example after edit, this no longer works.
function getValues() {
var input = document.getElementById('value').value;
// code to make ^ work like Math.pow
input = input.replace( '^', '**');
document.getElementById('result').innerHTML = eval(input);
}
The ** operator can replace the Math.pow function in most modern browsers. The next version of Safari (v10.1) coming out any day supports it.
As said in other answers here, you need a real parser to solve this correctly. A regex will solve simple cases, but for nested statements you need a recursive parser. For Javascript one library that offers this is peg.js.
In your case, the example given in the online version can be quickly extended to handle powers:
Expression
= head:Term tail:(_ ("+" / "-") _ Term)* {
var result = head, i;
for (i = 0; i < tail.length; i++) {
if (tail[i][1] === "+") { result += tail[i][3]; }
if (tail[i][1] === "-") { result -= tail[i][3]; }
}
return result;
}
Term
= head:Pow tail:(_ ("*" / "/") _ Pow)* { // Here I replaced Factor with Pow
var result = head, i;
for (i = 0; i < tail.length; i++) {
if (tail[i][1] === "*") { result *= tail[i][3]; }
if (tail[i][1] === "/") { result /= tail[i][3]; }
}
return result;
}
// This is the new part I added
Pow
= head:Factor tail:(_ "^" _ Factor)* {
var result = 1;
for (var i = tail.length - 1; 0 <= i; i--) {
result = Math.pow(tail[i][3], result);
}
return Math.pow(head, result);
}
Factor
= "(" _ expr:Expression _ ")" { return expr; }
/ Integer
Integer "integer"
= [0-9]+ { return parseInt(text(), 10); }
_ "whitespace"
= [ \t\n\r]*
It returns the expected output 7625597484987 for the input string (1+2)^3^3.
Here is a Python-based version of this question, with solution using pyparsing: changing ** operator to power function using parsing?

Automate replace a lot content strings in JavaScript

I have an string with HTML format, and I need to replace ALL the math exponents in HTML format <sup></sup>, to math exponents without HTML format.
I'm using the replace() method, but I need find and replace 100 exponents, from <sup>1</sup> to <sup>100</sup>, and I should write all the numbers (from 1 to 100).
var copiar = texto.
replace(/<br>/g, "\n").
replace(/<sup><\/sup>/g, "").
replace(/<sup>2<\/sup>/g, "²").
replace(/<sup>3<\/sup>/g, "³").
replace(/<sup>4<\/sup>/g, "⁴").
replace(/<sup>5<\/sup>/g, "⁵").
replace(/<sup>6<\/sup>/g, "⁶").
replace(/<sup>7<\/sup>/g, "⁷").
replace(/<sup>8<\/sup>/g, "⁸").
replace(/<sup>9<\/sup>/g, "⁹").
replace(/<sup>10<\/sup>/g, "¹⁰");
...
replace(/<sup>100<\/sup>/g, "¹⁰⁰");
My question is: There is a way to automate this task? Thanks!
UPDATE: I'm doing this replacements because I'm developing an App for iOS, capable to print (in HTML format) and copy to clipboard (plane text). That's the reason because I'm replacement the <sup> numbers.
UPDATE 14/Oct/2014: I was needing to replace negative exponents too. Using the #minitech answer and modifying a little, I could be able to replace ALL the exponents (positive and negative). Maybe can be useful for someone, here the code:
var map = '⁰¹²³⁴⁵⁶⁷⁸⁹';
var copiar = texto.replace(/<sup>(\-*(\d*))<\/sup>/g, function (str, digits){
return Array.prototype.map.call(digits, function (digit) {
var exp = "";
if (digit != '-') {
exp += map.charAt(digit);
} else {
exp += "¯";
}
return exp;
}).join('');
});
A string and charAt provide a convenient way to map digits to the corresponding superscript digits:
var map = '⁰¹²³⁴⁵⁶⁷⁸⁹';
var copiar = texto.replace(/<sup>(\d*)<\/sup>/g, function (_, digits) {
return Array.prototype.map.call(digits, function (digit) {
return map.charAt(+digit);
}).join('');
});
When you do a replacement, you can supply a function to calculate it, instead of a fixed string. So you can use a pattern for all your <sup> replacements, and use a function that translates the number to Unicode superscripts.
var copiar = texto.
replace(/<br>|<sup>(\d*)<\/sup>/g, function(match, digits) {
if (match == "<br>") {
return "\n";
}
// Rest is for translating superscripts to Unicode
var superdigits = '';
var zero = "0".charCodeAt(0);
var superzero = 0x2070;
var supertwo = 0x00b2;
for (var i = 0; i < digits.length; i++) {
var n = digits.charCodeAt(i) - zero;
var char;
switch (n) {
// Superscripts 2 and 3 are at weird places in Unicode
case 2: case 3:
char = String.fromCharCode(n - 2 + supertwo);
break;
default:
char = String.fromCharCode(n + superzero);
}
superdigits += char;
}
return superdigits;
});
<script>
function get_sup_index(num) {
var new_num = new String(num);
new_num = new_num.replace(/0/g, "⁰").
replace(/1/g, "¹").
replace(/2/g, "²").
replace(/3/g, "³").
replace(/4/g, "⁴").
replace(/5/g, "⁵").
replace(/6/g, "⁶").
replace(/7/g, "⁷").
replace(/8/g, "⁸").
replace(/9/g, "⁹");
return new_num;
}
var my_text = '<sup>1</sup>'+
'<sup>2</sup>'+
'<sup>3</sup>'+
'<sup>4</sup>'+
'<sup>5</sup>'+
'<sup>6</sup>'+
'<sup>7</sup>'+
'<sup>8</sup>'+
'<sup>9</sup>'+
'<sup>10</sup>';
alert(get_sup_index(my_text.replace(/<sup>([0-9]*)<\/sup>/g, "\$1")));
</script>
I hope that can help you.

Using parseFloat() or parseInt() and regex in JavaScript (converting a CSV file)

I'm converting a CSV file to a local 2D array. I wanted to know if there is a better way to convert strings to floats/int rather then using regex followed by a parseFloat() / parseInt.
Ideas / Suggestions?
// numex() - checkes to see if the string (str) is a number
// returns number.valid (true||false) and number.value = (float||int||string)
numex = function(str){
number = {};
number.valid = false;
number.value = str;
// if we see a number then convert it to a floating point or integer
if((number.value.search(/[^0-9^\.^\$^\%^\-^\"^,^ ]+/) < 0) && str.length > 0) {
number.valid = true;
number.value = str.replace(/[^\-^0-9^\.]+/g, ''); // TODO add % coversion code for example if we see a 10% covert it to .1
if(number.value.search(/[\.]/) >= 0) {
number.value = parseFloat(number.value); // replace floating point
} else {
number.value = parseInt(number.value); // replace integers
}
}
return number; // number.valid = true or false;
}
var num = numex("1.101");
alert(num.value);
I don't think you need to use regexp at all. Try this:
var num = {};
num.value = new Number(str);
num.valid = !isNaN(num.value);
Number constructor is more strict than parseInt and parseFloat in that it does not accept strings like 10aaa or 1.2bbb so there is no need to perform a regexp check.
I simplified the code greatly and used something similar to what LeZuse did.
isNaN(value) || value == ""
https://github.com/designpro/jCSV

JQuery/JavaScript increment number

I am trying to increment a number by a given value each second and retain the formatting using JavaScript or JQuery
I am struggling to do it.
Say I have a number like so:
1412015
the number which this can be incremented by each second is variable it could be anything beween 0.1 and 2.
Is it possible, if the value which it has to be incremented by each second is 0.54 to incremenet the number and have the following output:
1,412,016
1,412,017
1,412,018
Thanks
Eef
I'm not quite sure I understand your incrementation case and what you want to show.
However, I decided to chime in on a solution to format a number.
I've got two versions of a number format routine, one which parses an array, and one which formats with a regular expression. I'll admit they aren't the easiest to read, but I had fun coming up with the approach.
I've tried to describe the lines with comments in case you're curious
Array parsing version:
function formatNum(num) {
//Convert a formatted number to a normal number and split off any
//decimal places if they exist
var parts = String( num ).replace(/[^\d.]-/g,'').split('.');
//turn the string into a character array and reverse
var arr = parts[0].split('').reverse();
//initialize the return value
var str = '';
//As long as the array still has data to process (arr.length is
//anything but 0)
//Use a for loop so that it keeps count of the characters for me
for( var i = 0; arr.length; i++ ) {
//every 4th character that isn't a minus sign add a comma before
//we add the character
if( i && i%3 == 0 && arr[0] != '-' ) {
str = ',' + str ;
}
//add the character to the result
str = arr.shift() + str ;
}
//return the final result appending the previously split decimal place
//if necessary
return str + ( parts[1] ? '.'+parts[1] : '' );
}
Regular Expression version:
function formatNum(num) {
//Turn a formatted number into a normal number and separate the
//decimal places
var parts = String( num ).replace(/[^\d.]-/g,'').split('.');
//reverse the string
var str = parts[0].split('').reverse().join('');
//initialize the return value
var retVal = '';
//This gets complicated. As long as the previous result of the regular
//expression replace is NOT the same as the current replacement,
//keep replacing and adding commas.
while( retVal != (str = str.replace(/(\d{3})(\d{1,3})/,'$1,$2')) ) {
retVal = str;
}
//If there were decimal points return them back with the reversed string
if( parts[1] ) {
return retVal.split('').reverse().join('') + '.' + parts[1];
}
//return the reversed string
return retVal.split('').reverse().join('');
}
Assuming you want to output a formatted number every second incremented by 0.54 you could use an interval to do your incrementation and outputting.
Super Short Firefox with Firebug only example:
var num = 1412015;
setInterval(function(){
//Your 0.54 value... why? I don't know... but I'll run with it.
num += 0.54;
console.log( formatNum( num ) );
},1000);
You can see it all in action here: http://jsbin.com/opoze
To increment a value on every second use this structure:
var number = 0; // put your initial value here
function incrementNumber () {
number += 1; // you can increment by anything you like here
}
// this will run incrementNumber() every second (interval is in ms)
setInterval(incrementNumber, 1000);
This will format numbers for you:
function formatNumber(num) {
num = String(num);
if (num.length <= 3) {
return num;
} else {
var last3nums = num.substring(num.length - 3, num.length);
var remindingPart = num.substring(0, num.length - 3);
return formatNumber(remindingPart) + ',' + last3nums;
}
}
function rounded_inc(x, n) {
return x + Math.ceil(n);
}
var x = 1412015;
x = rounded_inc(x, 0.54);

Categories

Resources