checking two last elements - javascript

I'm doing my calculator and want prevent div to zero. I guess I must check last to elements if they are "/0"? what I'm doing wrong?
function div(input)
{
var input = document.getElementById("t");
var lastElement = (input.value.length-1);
//alert(input.value[lastElement-1]);
//alert(input.value[lastElement]);
if (input.value[lastElement-1] === "/")
{
if (input.value[lastElement] === "0")
{
alert(" / to Zero");
}
}
}

Use RegEx instead:
var is_div_by_zero = /\/[\s.0]+$/.test(value); // Returns true if it is divided by zero, false if otherwise
It matches:
/ 0
/0
/ 0
/ 000
/ 0.00000
etc.
As T.J. Crowder commented it is probably due to inconsistent formatting.

It would be better to work with the Javascript engine instead of going against it.
Just evaluate the entered formula and handle the exceptions thrown by the Javascript engine.
Place your evaluation code inside a try ... catch(e) block and handle the exceptions there.
try {
// your calculation code here, eg:
result = value1 / value2;
} catch (e) {
// this catches the error and provides the proper way of handling the errors,
// and your script doesn't die because of the error
// also, the e parameter contains the exception thrown, which provides info you can
// display
// or based on the error type come up with a proper solution
alert (e.message);
}
More info on Javascript error handling: http://javascript.info/tutorial/exceptions
Update
Forgot that, unfortunately, a division by zero does not result in an exception being thrown in Javascript. It will result in NaN for 0/0 and Infinity for x/0 (where x is any number). Infinity has the type number.
You can test for this after evaluating your equation.

My previous answer is one solution to your problem, but may bee too complicated for what would you like to achieve.
Instead of taking things from your input character by character, split your string on the operator and trim the parts. I will create the solution for two operands, and you can start from that.
var equation = document.getElementById("t").value;
var operands = equation.split('/');
var divisor = operands[operands.length - 1].trim();
// since the contents of your input are a string, the resulting element is also a string
if (parseFloat(divisor) == 0) {
alert("Division by zero");
}
This is a very rough approach, as you will have to validate and filter your input (no other things than numbers and valid operators should be allowed). Also, you will have to check for operation priority (do you allow multiple operators in your equation?) etc.

Related

Match a decimal number and replace non numeric characters in javascript

I am using the the following function in javascript.
function chknumber(a) {
a.value = a.value.replace(/[^0-9.]/g, '', '');
}
This function replaces any non numeric character entered in a textbox on whose onkeyup i have called the above function. The problem is it allows this string as well
1..1
I want the function to replace the second dot character as well. Any suggestions will be helpful.
I don't advocate simplistically modifying fields while people are trying to type in them, it's just too easy to interfere with what they're doing with simple handlers like this. (Validate afterward, or use a well-written, thoroughly-tested masking library.) When you change the value of a field when the user is typing in it, you mess up where the insertion point is, which is really frustrating to the user. But...
A second replace can correct .. and such:
function chknumber(a) {
a.value = a.value.replace(/[^0-9.]/g, '').replace(/\.{2,}/g, '.');
}
That replaces two or more . in a row with a single one. But, it would still allow 1.1.1, which you probably don't want. Sadly, JavaScript doesn't have lookbehinds, so we get into more logic:
function chknumber(a) {
var str = a.value.replace(/[^0-9.]/g, '').replace(/\.{2,}/g, '.');
var first, last;
while ((first = str.indexOf(".")) !== (last = str.lastIndexOf("."))) {
str = str.substring(0, last) + str.substring(last+1);
}
if (str !== a.value) {
a.value = str;
}
}
Can't guarantee there aren't other edge cases and such, and again, every time you assign a replacement to a.value, you're going to mess up the user's insertion point, which is surprisingly frustrating.
So, yeah: Validate afterward, or use a well-written, thoroughly-tested masking library. (I've had good luck with this jQuery plugin, if you're using jQuery.)
Side note: The second '' in your original replace is unnecessary; replace only uses two arguments.
try with match method if your input is "sajan12paul34.22" the match function will return a array contain [12 , 34.22]
the array index [0] is used for getting first numeric value (12)
function chknumber(a) {
a.value = a.value.match(/[0-9]*\.?[0-9]+/g)[0];
}

JavaScript if Statement .length not working. Why?

I have this if statement i have came up with here:
var TotalMoney=0;
var Orbs=0;
if (TotalMoney.length==2) {
Orbs+=1;
}
What this code is supposed to do is if the the "TotalMoney" value digit length equals 2,
example (the number 10 has 2 digits)
then it will add 1 "Orb" to the "Orbs" value. Currently, it does nothing. There is HTML and CSS linked to this code but i figured the problem is in this code as it works fine for everything else. Please fix it as i have been trying for hours. Thanks!
For my second question that i just found out with this code here:
var totalMoney=0;
var orbs=0;
if (totalMoney.toString().length==2) {
orbs+=1;
}
This works on getting the number value digits as 2 digits long. The problem now is that once it reaches 10, every time that number goes up (10-99) all the way up, it will add 1 orb each time. I only want it to add 1 orb only when it gets to the 2 digit number (10) and stops adding 1 orb after it reaches it. How can i achieve this? Thanks!
TotalMoney is a number, so it doesn't have a length property. You can check the length of the number by first converting to a string: TotalMoney.toString().length.
Number object in js has no length property, so TotalMoney.length return undefined.
If you want count digits you may use this:
if (TotalMoney.toString().length == 2) {
Orbs+=1;
}
But if TotalMoney will be negative, -1 for exmple, Orbs wil be incremented.
I think there are better way to find all 2-digits number:
if (TotalMoney>9 && TotalMoney<100) {
Orbs+=1;
}
TotalMoney is numeric
so to find its length use this code
TotalMoney.toString().length;
Instead of
TotalMoney.length;
so try to modify your code as below:
var TotalMoney=0;
var Orbs=0;
if (TotalMoney.toString().length==2) {
Orbs+=1;
}
Length is property of array & string.It can not be applied on other variables.
If you want to count number of digits you can do
if(TotalMoney>9)
Or you can convert it to string then check it's length
if(TotalMoney.toSting().length>2)
here are some ideas and general comments on your code.
// recommended to start with lower case. upper case such as 'TotalMoney'
// is stylistically reserved for constructors.
var totalMoney=0;
// again - changing form Orbs to orbs;
var orbs=0;
// recommended to use '===' until you are more experienced with JavaScript and
// know about the 'gotchas' that '==' might produce.
// you will be able to check the length of totalMoney only after converting it to a string.
if (totalMoney.toString().length === 2) {
orbs+=1;
}
Finally, totalMoney of 0 will not add one to orbs. But totalMoney of 10, as you mentioned, will.

Chai unittesting - expect(42).to.be.an('integer')

According to http://chaijs.com/api/bdd/#a, a/an can be used to check for the type of a variable.
.a(type)
#param{ String } type
#param{ String } message _optional_
The a and an assertions are aliases that can be used
either as language chains or to assert a value's type.
However, I'm not able to check for the variable beeing an integer. The given examples, e.g. expect('1337').to.be.a('string'); work for me, but the following does not:
expect(42).to.be.an('integer');
expect(42).to.be.an('Integer');
expect(42).to.be.an('int');
expect(42).to.be.an('Int');
All of them are giving me the following error when running mocha:
Uncaught AssertionError: expected 42 to be an integer
How do I test with chai for a variable beeing an integer?
A bit late, but for people coming from search engines, here is another solution:
var expect = require('chai').expect
expect(foo).to.be.a('number')
expect(foo % 1).to.equal(0)
The number check is required because of things such as true % 1 === 0 or null % 1 === 0.
JavaScript doesn't have a separate integer type.
Everything is a IEE 754 floating point number, which would of type number.
This is also possible (at least whithin node):
expect(42).to.satisfy(Number.isInteger);
Here is a more advanced example:
expect({NUM: 1}).to.have.property('NUM').which.is.a('number').above(0).and.satisfy(Number.isInteger);
I feel your pain, this is what I came up with:
var assert = require('chai').assert;
describe('Something', function() {
it('should be an integer', function() {
var result = iShouldReturnInt();
assert.isNumber(result);
var isInt = result % 1 === 0;
assert(isInt, 'not an integer:' + result);
});
});
Depending on the browser/context you are running in there is also a function hanging off of Number that would be of some use.
var value = 42;
Number.isInteger(value).should.be.true;
It has not been adopted everywhere, but most of the places that matter (Chrome, FFox, Opera, Node)
More Info here
Another [not optimal] solution (why not?!)
const actual = String(val).match(/^\d+$/);
expect(actual).to.be.an('array');
expect(actual).to.have.lengthOf(1);

Apparent trouble with behavior of substring in JavaScript

I am writing a recursive algorithm to build a finite state automaton by parsing a regular expression. The automaton iterates through the expression, pushing characters to a stack and operators to an "operator stack." When I encounter "(" (indicating a grouping operation), I push a "sub automaton" to the stack and pass the rest of the pattern to the sub automaton to parse. When that automaton encounters ")", it passes the rest of the string up to the parent automaton to finish parsing. Here is the code:
var NFA = function(par) {
this.stack = [];
this.op_stack = [];
this.parent = par;
};
NFA.prototype.parse = function(pattern) {
var done = false;
for(var i in pattern) {
if (done === true) {
break;
}
switch(pattern.charAt(i)) {
case "(":
var sub_nfa = new NFA(this);
this.stack.push(sub_nfa);
sub_nfa.parse(pattern.substring(i+1, pattern.length));
done = true;
break;
case ")":
if (this.parent !== null) {
var len = pattern.length;
/*TROUBLE SPOT*/
this.parent.parse(pattern.substring(i, pattern.length));
done = true;
break;
}
case "*":
this.op_stack.push(operator.KLEENE);
break;
case "|":
this.op_stack.push(operator.UNION);
break;
default:
if(this.stack.length > 0) {
//only push concat after we see at least one symbol
this.op_stack.push(operator.CONCAT);
}
this.stack.push(pattern.charAt(i));
}
}
};
Note the area marked "TROUBLE SPOT". Given the regular expression "(a|b)a", the call this.parent.parse, is called exactly once: when the sub-automaton encounters ")". At this point, pattern.substring(i, pattern.length) = ")a". This "works", but it isn't correct because I need to consume the ")" input before I pass the string to the parent automaton. However, if I change the call to this.parent.parse(pattern.substring(i+1, pattern.length), parse gets handed the empty string! I have tried stepping through the code and I cannot explain this behavior. What am I missing?
At Juan's suggestion, I made a quick jsfiddle to show the problem when trying to parse "(a|b)a" with this algorithm. In the ")" case, it populates an empty div with the substring at the i index and the substring at the i+1 index. It shows that while there are 2 characters in the substring at i, the substring at i+1 is the empty string! Here's the link: http://jsfiddle.net/XC6QM/1/
EDIT: I edited this question to reflect the fact that using charAt(i) doesn't change the behavior of the algorithm.
I think the previous answer was on the right track. But there also looks to me to be an off-by-one error. Shouldn't you be increasing the index for your substring? You don't want to include the ")" in the parent parse, right?
this.parent.parse(pattern.substring(i + 1, pattern.length));
But this will still fail because of the error Juan mentioned. A quick temporary fix to test this would be to convert the i to a number:
this.parent.parse(pattern.substring(+i + 1, pattern.length));
This might do it for you. But you should probably go back and switch away from the for-in loop on the string. I think that's causing your issue. Turn it into an array with str.split('') and then use an integer to loop. That will prevent further such issues.
The real problem is the fact that you were using a for in to iterate through the characters of the string. With the for in loop, your i is going to be a string, therefore, when you try to do i+1, it does string concatenation.
If you change your iteration to be
for(var i=0; i < pattern.length; i++) {
Then it all works fine http://jsfiddle.net/XC6QM/2/
Scott's answer correctly identified the problem but I think his solution (converting the indexes to numbers) is not ideal. You're better off looping with a numeric index to begin with
Also, you should not use brackets to access characters within a string, that does not work in IE 7
switch(pattern[i]) {
should be
switch(pattern.charAt(i)) {

Counting words separated by comma

My counter function looks like that
function count() {
var value = ids.val();
return (value == '') ? 0 : value.replace(/\s,?|,$/g, '').split(',').length;
}
Then checking for returned value and posting data via ajax
if(count() === 10){
ajaxPost();
$(ids).val('');
}
I set interval to use this function. Noting that, tried all other function like change(),paste().. the only way that worked with my scanner device is, to set interval.
The problem is, when i type 9 numbers, like 1...9 and then want to type 10, when I press 1 to write 10 right after 9, it directly posts data. doesn't wait for ",". How can I modify it to wait for "," after last (in this case 10th) word?
You can check the key pressed and see if it is a comma, then only run your code after it is known that the last key entered was a comma:
$(ids).on('keyup', function (event) {
if (event.which == 188) {
if (count(this.value) === 10) {
ajaxPost();
ids.value = '';
}
}
});
10 words with a trailing comma give you 10 commas, consequently, 11 elements in the split result array (the last element will be empty if comma is the last character of the input). Check it like if (count() === 11)....
This should work...
var count = function(str){
var matches = str.match(/.*?,/g);
return (matches == null)? 0 : matches.length;
};
Also you can probably use the keyup or keydown methods to catch this event rather than using a setInterval.
If I were you, I would put this code into a keypress handler. That way it would only be invoked when you type new characters. To prevent it from running the check too often, use _.debounce. Finally, as Andrew mentioned, ",,,,,,,,,,".split(',').length == 11. It appears that you are sabotaging yourself with that regular expression that looks for an optional final comma.
Not sure if I've understood your question completely, but...
You want to wait for a last "," to make sure that all numbers were typed by your scanner? Or you need to get that 10 but the interval occurs just before the scanner finished writing it?
If it is the second case, I recommend you to restart the interval at every keyPressed event. Doing that, you'll give some time just after the key was pressed to wait in case any other key is pressed too.
So, you'll have something like this:
var lastInterval = null
$(ids).keyPress(function() {
if(lastInterval != null)
clearTimeout(lastInterval)
lastInterval = setInterval(function() {
// ... your code here
}, 1000)
})
Is this clear? Hope it helps :)
--- EDIT
Ok, it's weird that a barcode scanner doesn't trigger keyPress events, but taking this as a premise, you could check for changes in the string, and when the string didn't change in N cycles, you trigger your code.
In this example, you'll be sure that the string remained equal at least 1000 ms (between 1000ms and 1999ms).
var lastString = ""
setInterval(function() {
if(lastString == $(ids).val()) { // So, if the value remains the same for 2 cycles, the second one your code will be evaluated
// ... your code here
}
lastString = $(ids).val()
}, 1000)

Categories