Running an equation from a string - javascript

I am trying to create a simple online calculator that can run basic calculations in JavaScript.
I have managed to create the interface so that numbers and operators and stored in a form field.
What I would like to be able to do is pass the values within the form field to a function that will calculate the total of the form field.
The form field could contain anything from a simple "10 + 10" to more complex equations using brackets. The operators in use are +, -, *, and /.
Is it possible to pass the form field's text (a string) to a JavaScript function that can recognize the operators and the perform the function of the operation on the values?
A possible value in the text field would be:
120/4+130/5
The function should then return 56 as the answer. I have done this in JavaScript when I know the values like this:
function WorkThisOut(a,b,c,d) {
var total = a/b+c/d;
alert (total);
}
WorkThisOut(120,4,130,5);
What I would like to be able to do is pass the full value "120/4+130/5" to the function and it be able to extract the numbers and operators to create the total.
Does anyone have any ideas on how this could be done or if it is even possible? this may get more complex where I may need to pass values in parentheses "(120/4)+(130/5)"

I may get blasted for this. But, here it goes anyway.
There are three solutions I can think of for this:
Implement your own parser, lexer and parse out the code.
That's not super easy, but it may be a great learning experience.
Run an eval under a subdomain meant only for that, so that scripts can't maliciously access your site
Sanitize the input to contain only 12345678790+-/*().
eval(input.replace(/[^0-9\(\)\+\-\*\/\.]/g, ""));
Please blast away with tricks to get around this solution

You can use the expression parser included with the math.js library:
http://mathjs.org
Example usage:
math.eval('1.2 / (2.3 + 0.7)'); // 0.4
math.eval('5.08 cm in inch'); // 2 inch
math.eval('sin(45 deg) ^ 2'); // 0.5
math.eval('9 / 3 + 2i'); // 3 + 2i
math.eval('det([-1, 2; 3, 1])'); // -7

It is pretty hard to do much damage with eval if you don't allow identifiers.
function reval(string){
var answer='';
if(/^[\d()\/*.+-]+$/.test(str)){
try{
answer= eval(str);
}
catch(er){
answer= er.name+', '+er.message;
}
}
return answer;
}

what about eval?
consider calc as the id of textfield. then
$('#calc').change(function(e){
alert(eval($(this).val()));
})
but remember to validate input before processing.

This is a pretty old topic, but for the new visitors who have similar problem: the string-math package calculates the [String] equations like in the sample above 120/4+130/5. It also recognizes parentheses.

Related

Remove a character in C#

System.FormatException: Input string was not in a correct format.
it is because the input expected should be numbers only but my input must be in the format of 555-555-5555 that is a requirement. here is my js to do so:
$(window).load(function () {
$("#phoneNumber").inputmask("***-***-****");
});
And here is my C# to render the value in this format (555)555-5555, the issue happens here
public static string phoneFormat(string phone)
{
//string[] splitNr = phone.Split('-');
// return ("(" + splitNr[0] + ")" + splitNr[1] + "-" + splitNr[2]);
string[] number = phone.Split();
return string.Format("{0:(###) ### - ####}",ulong.Parse(phone));//ERROR
}
if i use the commented out part it works but i want to use the parse way. How do i remove the "-" in C# after user input it in the UI and then display the number in this format (555)555-5555.
Thank you
It is easier to handle it as a string instead of trying to parse and then format it as number:
return Regex.Replace(phone, #"(\d{3})-(\d{3})-(\d{4})", "($1) $2 - $3")
For fun we can do this:
return string.Format("{0:(###) ### - ####}",ulong.Parse(phone.Replace("-", "")));
But what I'd really do is remove the input mask. Yes, use html/javascript to help the user put in good data, but do so in a way that's much more permissive. If I put in 5551234567, 555.123.4567, (555)123-4567, or even much worse, you should be able to handle any of those.
Input masks are usually bad UI/UX.
On the C# end, I'd really separate this into two parts: normalization, where I clean up potentially messy input for storage and validation, and formatting, where I take the normalized data and format it for display. The reason for two steps is because it's often much more efficient in terms of storage and indexing to store a basic (unformatted) value. Even better, sometimes users want to see the same data represented in different ways. Now it's easy for me to have different format options for the same value. Some people will also include validation as it's own phase, but I like to do this as part of normalizing the data.
Thus, for a really basic phone number, I'd handle the code like this:
public static string NormalizePhone(string phone)
{
// **We should give the user the benefit of the doubt.**
// I don't care what crazy format they used, if there are 10 digits, we can handle it.
//remove anything not a digit
var digits = Regex.Replace(phone, #"[^\d]", "");
//ensure exactly 10 characters remain
if (digits.Length != 10) throw new InvalidArgumentException($"{phone} is not a valid phone number in this system.");
return digits;
}
// Phone argument should be pre-normalized,
// because we want to be able to use this method with strings retrieved
// from storage without having to re-normalize them every time.
// Remember, you'll show a repeat value more often than you receive new values.
public static string FormatPhone(string phone)
{
//Even better if you have an Assert() here that can show phone is always pre-normalized in testing, but works to a no-op in production.
return Regex.Replace(phone, #"(\d{3})(\d{3})(\d{4})", "($1) $2 - $3");
}
Now your existing code can call them together:
try
{
FormatPhone(NormalizePhone(phone));
}
catch(InvalidArgumentException ex)
{
// This won't happen often.
// The html/js layer should stop it in most cases,
// such that we meet the rule of reserving exception handling for actual exceptional events.
// But you'll still want to add a meaningful handler here.
}
But really, I would call NormalizePhone() by itself, to have that raw value ready to save to the user's record, and then FormatPhone() afterwards, to show the user on the screen.
Finally, this is a simplistic port. Real phone number validation can be quite complicated. The link is pretty much the standard work in the area, and it's a whopping 12Mb of raw code.

Javascript - Function Not Defined (but it is!) after finishing JQuery function

I have a piece of JavaScript code that keeps throwing an 'Is Undefined' error.
< script language = "javascript"
type = "text/javascript" >
// fuction added for click on submit - dp0jmr 05/23/2018
function checkScheduleAndAmount() {
var ppAmt = (double)
<%=p.getPaymentPlanAmt()%>;
var totalamt = (double) document.getElementById("sum").innerText;
if (ppAmt != totalamt) {
alert("The Payment Plan Schedule does not add up to the total Payment Plan Amount - this Payment Plan cannot be submitted." +
" Please correct the Amounts entered and submit the Payment Plan Schedule before leaving this page." +
"\n\nIf the Date Range you have entered does not allow you to enter the Plan you desire, please End this Payment Plan " +
"and begin a new one." +
"\n\nIf you know the installment amount you wish to use, you can enter an installment amount at the start of a new " +
"Payment Plan, and the application will calculate the final payoff date for you. ");
return false;
} else {
return true;
}
}
<
/script>
I've eliminated as many possible culprits as I could:
I've tried every combination of script definitions - there is some JQuery in addition to this JavaScript, but it was running fine alongside it until recently.
I tried putting it inside the page element with no effect.
I don't see any obvious syntax errors - all the variables being used here are defined.
The function call is on an html:button tag, at the very bottom of the div.
<html:submit property="submitValue" value="<%=PaymentPlanDetailsForm.SUBMIT%>" styleClass="button" disabled="<%=isActive %>" onclick="return checkScheduleAndAmount()" onkeypress="return false"/>
This started to occur recently after refining my JQuery function, but both functions seemed to be working fine during testing, and even seemed to work without issue together for awhile - and unfortunately, I cannot revert my changes now because I made the mistake of closing the IDE. :(
Am I missing something obvious in the syntax for this? Or is there another reason my page isn't recognizing my javascript function?
This JavaScript code:
var totalamt = (double) document.getElementById("sum").innerText;
...is invalid JavaScript code, and so the parsing fails, and the function isn't created.
JavaScript is not C# or Java or (insert language here). It doesn't have casting. Just remove the (double) part. If you want to convert that string to a number, use a unary +, the Number function, parseInt, or parseFloat.
For instance, if you want to convert all of the text to a number, and treat a blank as an invalid input, then:
var str = document.getElementById("sum").innerText;
var totalamt = str ? +str : NaN;
if (isNaN(totalamt)) {
// ...it wasn't a valid number
}
As I mentioned, you could also use parseInt or parseFloat, but beware that they accept numbers with trailing non-numeric characters (parseFloat("123.4abc") is 123.4, for instance).

Why doesn't my function correctly replace when using some regex pattern

This is an extension of this SO question
I made a function to see if i can correctly format any number. The answers below work on tools like https://regex101.com and https://regexr.com/, but not within my function(tried in node and browser):
const
const format = (num, regex) => String(num).replace(regex, '$1')
Basically given any whole number, it should not exceed 15 significant digits. Given any decimal, it should not exceed 2 decimal points.
so...
Now
format(0.12345678901234567890, /^\d{1,13}(\.\d{1,2}|\d{0,2})$/)
returns 0.123456789012345678 instead of 0.123456789012345
but
format(0.123456789012345,/^-?(\d*\.?\d{0,2}).*/)
returns number formatted to 2 deimal points as expected.
Let me try to explain what's going on.
For the given input 0.12345678901234567890 and the regex /^\d{1,13}(\.\d{1,2}|\d{0,2})$/, let's go step by step and see what's happening.
^\d{1,13} Does indeed match the start of the string 0
(\. Now you've opened a new group, and it does match .
\d{1,2} It does find the digits 1 and 2
|\d{0,2} So this part is skipped
) So this is the end of your capture group.
$ This indicates the end of the string, but it won't match, because you've still got 345678901234567890 remaining.
Javascript returns the whole string because the match failed in the end.
Let's try removing $ at the end, to become /^\d{1,13}(\.\d{1,2}|\d{0,2})/
You'd get back ".12345678901234567890". This generates a couple of questions.
Why did the preceding 0 get removed?
Because it was not part of your matching group, enclosed with ().
Why did we not get only two decimal places, i.e. .12?
Remember that you're doing a replace. Which means that by default, the original string will be kept in place, only the parts that match will get replaced. Since 345678901234567890 was not part of the match, it was left intact. The only part that matched was 0.12.
Answer to title question: your function doesn't replace, because there's nothing to replace - the regex doesn't match anything in the string. csb's answer explains that in all details.
But that's perhaps not the answer you really need.
Now, it seems like you have an XY problem. You ask why your call to .replace() doesn't work, but .replace() is definitely not a function you should use. Role of .replace() is replacing parts of string, while you actually want to create a different string. Moreover, in the comments you suggest that your formatting is not only for presenting data to user, but you also intend to use it in some further computation. You also mention cryptocurriencies.
Let's cope with these problems one-by-one.
What to do instead of replace?
Well, just produce the string you need instead of replacing something in the string you don't like. There are some edge cases. Instead of writing all-in-one regex, just handle them one-by-one.
The following code is definitely not best possible, but it's main aim is to be simple and show exactly what is going on.
function format(n) {
const max_significant_digits = 15;
const max_precision = 2;
let digits_before_decimal_point;
if (n < 0) {
// Don't count minus sign.
digits_before_decimal_point = n.toFixed(0).length - 1;
} else {
digits_before_decimal_point = n.toFixed(0).length;
}
if (digits_before_decimal_point > max_significant_digits) {
throw new Error('No good representation for this number');
}
const available_significant_digits_for_precision =
Math.max(0, max_significant_digits - digits_before_decimal_point);
const effective_max_precision =
Math.min(max_precision, available_significant_digits_for_precision);
const with_trailing_zeroes = n.toFixed(effective_max_precision);
// I want to keep the string and change just matching part,
// so here .replace() is a proper method to use.
const withouth_trailing_zeroes = with_trailing_zeroes.replace(/\.?0*$/, '');
return withouth_trailing_zeroes;
}
So, you got the number formatted the way you want. What now?
What can you use this string for?
Well, you can display it to the user. And that's mostly it. The value was rounded to (1) represent it in a different base and (2) fit in limited precision, so it's pretty much useless for any computation. And, BTW, why would you convert it to String in the first place, if what you want is a number?
Was the value you are trying to print ever useful in the first place?
Well, that's the most serious question here. Because, you know, floating point numbers are tricky. And they are absolutely abysmal for representing money. So, most likely the number you are trying to format is already a wrong number.
What to use instead?
Fixed-point arithmetic is the most obvious answer. Works most of the time. However, it's pretty tricky in JS, where number may slip into floating-point representation almost any time. So, it's better to use decimal arithmetic library. Optionally, switch to a language that has built-in bignums and decimals, like Python.

How to compare locale dependent float numbers?

I need to compare a float value entered in a web form against a range. The problem is that the client computers may have various locale settings, meaning that user may use either "." or "," to separate the integer part from decimal one.
Is there a simple way to do it? As it is for an intranet and that they are only allowed to use IE, a VBScript is fine, even if I would prefer to use JavaScript.
EDIT: Let me clarify it a bit:
I cannot rely on the system locale, because, for example, a lot of our french customers use a computer with an english locale, even if they still use the comma to fill data in the web forms.
So I need a way to perform a check accross multiple locale "string to double" conversion.
I know that the raise condition is "what about numbers with 3 decimal digits", but in our environment, this kind of answer never happen, and if it happens, it will be threated as an out of range error due to the multiplication by a thousand, so it's not a real issue for us.
In Javascript use parseFloat on the text value to get a number. Similarly in VBScript use CDbl on the text value. Both should conform to the current locale settings enforce for the user.
This code should work:
function toFloat(localFloatStr)
var x = localFloatStr.split(/,|\./),
x2 = x[x.length-1],
x3 = x.join('').replace(new RegExp(x2+'$'),'.'+x2);
return parseFloat(x3);
// x2 is for clarity, could be omitted:
//=>x.join('').replace(new RegExp(x[x.length-1]+'$'),'.'+x[x.length-1])
}
alert(toFloat('1,223,455.223')); //=> 1223455.223
alert(toFloat('1.223.455,223')); //=> 1223455.223
// your numbers ;~)
alert(toFloat('3.123,56')); //=> 3123.56
alert(toFloat('3,123.56')); //=> 3123.56
What we do is try parsing using the culture of the user and if that doesn't work, parse it using an invariant culture.
I wouldn't know how to do it in javascript or vbscript exactly though.
I used KooiInc's answer but change it a bit, because it didn't reckon with some cases.
function toFloat(strNum) {
var full = strNum.split(/[.,]/);
if (full.length == 1) return parseFloat(strNum);
var back = full[full.length - 1];
var result = full.join('').replace(new RegExp(back + '$'), '.' + back);
return parseFloat(result);
}
Forbid using any thousands separator.
Give the user an example: "Reals should look like this: 3123.56 or 3123,56". Then simply change , to . and parse it.
You can always tell user that he did something wrong with a message like this:
"I don't understand what you mean by "**,**,**".
Please format numbers like "3123.56."

Javascript percentage validation

I am after a regular expression that validates a percentage from 0 100 and allows two decimal places.
Does anyone know how to do this or know of good web site that has example of common regular expressions used for client side validation in javascript?
#Tom - Thanks for the questions. Ideally there would be no leading 0's or other trailing characters.
Thanks to all those who have replied so far. I have found the comments really interesting.
Rather than using regular expressions for this, I would simply convert the user's entered number to a floating point value, and then check for the range you want (0 to 100). Trying to do numeric range validation with regular expressions is almost always the wrong tool for the job.
var x = parseFloat(str);
if (isNaN(x) || x < 0 || x > 100) {
// value is out of range
}
I propose this one:
(^100(\.0{1,2})?$)|(^([1-9]([0-9])?|0)(\.[0-9]{1,2})?$)
It matches 100, 100.0 and 100.00 using this part
^100(\.0{1,2})?$
and numbers like 0, 15, 99, 3.1, 21.67 using
^([1-9]([0-9])?|0)(\.[0-9]{1,2})?$
Note what leading zeros are prohibited, but trailing zeros are allowed (though no more than two decimal places).
This reminds me of an old blog Entry By Alex Papadimoulis (of The Daily WTF fame) where he tells the following story:
"A client has asked me to build and install a custom shelving system. I'm at the point where I need to nail it, but I'm not sure what to use to pound the nails in. Should I use an old shoe or a glass bottle?"
How would you answer the question?
It depends. If you are looking to pound a small (20lb) nail in something like drywall, you'll find it much easier to use the bottle, especially if the shoe is dirty. However, if you are trying to drive a heavy nail into some wood, go with the shoe: the bottle with shatter in your hand.
There is something fundamentally wrong with the way you are building; you need to use real tools. Yes, it may involve a trip to the toolbox (or even to the hardware store), but doing it the right way is going to save a lot of time, money, and aggravation through the lifecycle of your product. You need to stop building things for money until you understand the basics of construction.
This is such a question where most people sees it as a challenge to come up with the correct regular expression to solve the problem, but it would be much better to just say that using regular expressions are using the wrong tool for the job.
The problem when trying to use regex to validate numeric ranges is that it is hard to change if the requirements for the allowed range is changes. Today the requirement may be to validate numbers between 0 and 100 and it is possible to write a regex for that which doesn't make your eyes bleed. But next week the requirment maybe changes so values between 0 and 315 are allowed. Good luck altering your regex.
The solution given by Greg Hewgill is probably better - even though it would validate "99fxx" as "99". But given the circumstances that might actually be ok.
Given that your value is in str
str.match(/^(100(\.0{1,2})?|([0-9]?[0-9](\.[0-9]{1,2})))$/)
^100(\.(0){0,2})?$|^([1-9]?[0-9])(\.(\d{0,2}))?\%$
This would match:
100.00
optional "1-9" followed by a digit (this makes the int part), optionally followed by a dot and two digits
From what I see, Greg Hewgill's example doesn't really work that well because parseFloat('15x') would simply return 15 which would match the 0<x<100 condition. Using parseFloat is clearly wrong because it doesn't validate the percentage value, it tries to force a validation. Some people around here are complaining about leading zeroes and some are ignoring trailing invalid characters. Maybe the author of the question should edit it and make clear what he needs.
I recomend this, if you are not exclusively developing for english speaking users:
[0-9]{1,2}((,|\.)[0-9]{1,10})?%?
You can simply replace the 10 by a 2 to get two decimal places.
My example will match:
15.5
5.4366%
1,43
50,55%
34
45%
Of cause the output of this one is harder to cast, but something like this will do (Java Code):
private static Double getMyVal(String myVal) {
if (myVal.contains("%")) {
myVal = myVal.replace("%", "");
}
if (myVal.contains(",")) {
myVal = myVal.replace(',', '.');
}
return Double.valueOf(myVal);
}
None of the above solutions worked for me, as I needed my regex to allow for values with numbers and a decimal while the user is typing ex: '18.'
This solution allows for an empty string so the user can delete their entire input, and accounts for the other rules articulated above.
/(^$)|(^100(\.0{1,2})?$)|(^([1-9]([0-9])?|0)\.(\.[0-9]{1,2})?$)|(^([1-9]([0-9])?|0)(\.[0-9]{1,2})?$)/
(100|[0-9]{1,2})(\.[0-9]{1,2})?
That should be the regex you want. I suggest you to read Mastering Regular Expression and download RegexBuddy or The Regex Coach.
#mlarsen:
Is not that a regex here won't do the job better.
Remember that validation msut be done both on client and on server side, so something like:
100|(([1-9][0-9])|[0-9])(\.(([0-9][1-9])|[1-9]))?
would be a cross-language check, just beware of checking the input length with the output match length.
(100(\.(0){1,2})?|([1-9]{1}|[0-9]{2})(\.[0-9]{1,2})?)

Categories

Resources