Links: https://github.com/VirxEC/CalcPlus/blob/master/assets/Library.js and https://virxec.github.io/CalcPlus/PreviewLibrary/ these are just links to the main code if needed. The first link is the source, the second is the run environment.
The function expo has a very critical issue. I will explain what it does, then I will explain the exact issue and what I've tried to fix it. So the function is meant to calculate exponents up to 264-1 digits long. (For the answer.) It works by running the multiplication function multiple times (on lines 196-197: final = multi(num1, num1); for (var i="2"; isLessThan(i, num2); i=add({num:i.split(""),isNeg:false,decimals:0}, {num:["1"],isNeg:false,decimals:0})) final = multi(final, num1);)
The objects that you see are passed into the isLessThan() function are examples of me passing pre-parsed numbers to the function doesn't have to re-parse them and take up computer resources. This passing of a pre-parsed object is where the error is. On line 197, you can see final = multi(final, num1); The final variable is not pre-parsed for obvious reasons, but num1 is. However, if you go into the chrome debugger and watch the num1 variable, the multi() function changes the content of the property num1.num from (if you did 264) from ["2"] to ["0","2"] causing and incorrect answer.
I've tested force-removing this behavior is intended for the multi function, but it shouldn't be modifying the argument. I've tried naming the variable something else, using const, and trying to set the object to be read-only nothing has worked. I've even tried something like this:
num1save = num1;
final = multi(num1, num1);
for (var i="2"; isLessThan(i, num2); i=add({num:i.split(""),isNeg:false,decimals:0}, {num:["1"],isNeg:false,decimals:0})) {
final = multi(final, num1);
num1 = num1save;
}
However, somehow, the variable manages to change num1save. Any variable referenced at some point to the object is changed. I have no idea why this is happening. This same thing happens with the isLessThan() function and the variable num2 on line 197.
This includes only the required code, so the lines won't match up:
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
// https://github.com/VirxEC/CalcPlus/blob/master/LICENSE
function parseNums(num1pre, num2pre, mode) {
if (["string", "object"].indexOf(typeof num1pre) == -1) throw new TypeError("The first number wasn't a string (or object). It has to be a string (or object). Note that an object input is ment to submit a pre-parsed number.");
if (["string", "object"].indexOf(typeof num2pre) == -1) throw new TypeError("The second number wasn't a string (or object). It has to be a string (or object). Note that an object input is ment to submit a pre-parsed number.");
if (typeof mode != "number" || [1, 2, 3, 4, 5].indexOf(mode) == -1) throw new TypeError("The mode must be a number from 1-5.");
var num1 = num1pre,
num2 = num2pre,
skip = false,
stringMode1 = true,
stringMode2 = true,
neg = [false, false, false],
decimal = 0,
decimal1 = 0,
decimal2 = 0,
num1pos, num2pos, maxChar, numl;
if (num1.num != undefined) neg[1] = num1pre.isNeg, decimal1 = num1pre.decimals, num1 = num1pre.num, stringMode1 = false;
if (num2.num != undefined) neg[2] = num2pre.isNeg, decimal2 = num2pre.decimals, num2 = num2pre.num, stringMode2 = false;
if (stringMode1 && num1.split("-").length == 2) num1 = num1.split("-")[1], neg[1] = true;
if (stringMode2 && num2.split("-").length == 2) num2 = num2.split("-")[1], neg[2] = true;
if (neg[1] != neg[2] && mode != 1 && mode != 2) neg[0] = true;
if (stringMode1) num1 = num1.split('').filter(w => w != ",");
if (stringMode2) num2 = num2.split('').filter(w => w != ",");
num1pos = num1.indexOf("."), decimal1 = num1pos != -1 ? num1.filter(w => w != ".").length - num1pos : 0, num2pos = num2.indexOf("."), decimal2 = num2pos != -1 ? num2.filter(w => w != ".").length - num2pos : 0, decimal = mode == 1 || mode == 2 ? Math.max(decimal1, decimal2) : mode == 3 ? decimal1 + decimal2 : decimal1 - decimal2, maxChar = Math.max(num1.length, num2.length);
for (var i = 0; !skip && num2.length == maxChar && i < num2.length && (((neg[1] || neg[2]) && mode == 1) || mode == 2); i++)
if (+num2[i] > +num1[i]) neg[0] = true, skip = true;
if (decimal < 0) decimal = 0;
if (maxChar == num2.length && mode == 3) num1 = [num2, num2 = num1][0]
if (decimal1 != decimal2 && [1, 2].indexOf(mode) > -1) {
if (decimal1 == decimal)
for (var i = 0; i < decimal1 - decimal2; i++) num2.push("0");
else if (decimal2 == decimal)
for (var i = 0; i < decimal2 - decimal1; i++) num1.push("0");
}
if (num1.length != num2.length && [1, 2].indexOf(mode) > -1) {
numl = [num1.length, num2.length];
if (maxChar == numl[0])
for (var i = 0; i < numl[0] - numl[1]; i++) num2.unshift("0");
else if (maxChar != num1[0])
for (var i = 0; i < numl[1] - numl[0]; i++) num1.unshift("0");
}
if (mode == 3 && neg.every(e => (e == true))) neg[0] = false;
return {
num1: {
num: num1,
isNeg: neg[1],
decimals: decimal1
},
num2: {
num: num2,
isNeg: neg[2],
decimals: decimal2
},
isNeg: neg[0],
maxChar: maxChar,
decimals: decimal
};
}
function formatNums(final, decimals, neg) {
if (typeof final == "string") {
if (decimals > 0) {
final = final.split("");
final.splice(final.length - decimals, 0, ".");
final = final.join("");
}
} else if (typeof final == "object") {
if (decimals > 0) {
final = final.reverse();
final.splice(final.length - decimals, 0, ".");
final = final.join("");
} else final = final.reverse().join("");
}
final = neg[0] ? "-" + final : final;
final = ["", ".", "-"].indexOf(final) > -1 ? "0" : final;
return final;
}
function add() {
function tempadd(num1, num2) {
var parsedNums = parseNums(num1, num2, 1),
neg = [parsedNums.isNeg, parsedNums.num1.isNeg, parsedNums.num2.isNeg],
maxChar = parsedNums.maxChar,
decimal = [parsedNums.decimals, parsedNums.num1.decimals, parsedNums.num2.decimals],
num1 = parsedNums.num1.num,
num2 = parsedNums.num2.num,
time, final = [],
carry = "0",
finali;
if (neg[2]) return sub(parsedNums.num1, {
num: num2,
isNeg: false,
decimals: decimal[1]
});
else if (neg[1]) return sub(parsedNums.num2, {
num: num1,
isNeg: false,
decimals: decimal[2]
});
for (var i = maxChar - 1; i >= 0; i--) {
finali = maxChar - i - 1;
if (time != i + 1) carry = "0";
final[finali] = String(+num1[i] + (+num2[i]) + (+carry));
if (+final[finali] > 9) {
var temp = final[finali].split('');
final[finali] = temp[1], carry = temp[0], time = i;
if (i - 1 < 0) final.push(carry);
}
}
return formatNums(final, decimal[0], neg);
}
var permfinal, a = arguments;
if (Array.isArray(a[0])) a = a[0];
permfinal = tempadd(a[0], a[1]);
for (var i = 2; i < a.length; i++) permfinal = tempadd(permfinal, a[i]);
return permfinal;
}
function sub() {
function tempsub(num1pre, num2pre) {
var parsedNums = parseNums(num1pre, num2pre, 2),
neg = [parsedNums.isNeg, parsedNums.num1.isNeg, parsedNums.num2.isNeg],
maxChar = parsedNums.maxChar,
decimal = [parsedNums.decimals, parsedNums.num1.decimals, parsedNums.num2.decimals],
num1 = parsedNums.num1.num,
num2 = parsedNums.num2.num,
final = [],
finali, fans;
if (neg[0] && !neg[1] && !neg[2]) num1 = [num2, num2 = num1][0];
else if (neg[1] && neg[2]) num1 = [num2, num2 = num1][0];
else if (neg[2] && !neg[1]) return add(parsedNums.num1, {
num: num2,
isNeg: false,
decimals: decimal[2]
});
else if (neg[1] && !neg[2]) return "-" + add({
num: num1,
isNeg: false,
decimals: decimal[1]
}, parsedNums.num2);
for (var i = maxChar - 1; i >= 0; i--) {
finali = maxChar - i - 1, fans = num1[i] - num2[i];
if (fans < 0 && i != 0) {
var j = i - 1;
final[finali] = String(fans + 10), num1[j] = String(num1[j] - 1);
while (num1[j] < 0 && j != 0) num1[j] = String((+num1[j]) + 10), j = j - 1, num1[j] = String(num1[j] - 1);
} else if (fans < 0 && i == 0) final[finali] = String(fans).split("-")[1];
else final[finali] = fans;
}
return formatNums(final, decimal[0], neg);
}
var permfinal, a = arguments;
if (Array.isArray(a[0])) a = a[0];
permfinal = tempsub(a[0], a[1]);
for (var i = 2; i < a.length; i++) permfinal = tempsub(permfinal, a[i]);
return permfinal;
}
function isLessThan() {
function templessthan(num1, num2) {
var num = sub(num2, num1);
if (num.split("-").length == 1 && num != 0) return true;
return false;
}
var permfinal, a = arguments;
if (Array.isArray(a[0])) a = a[0];
permfinal = templessthan(a[0], a[1]);
for (var i = 2; i < a.length; i++) permfinal = templessthan(permfinal, a[i]);
return permfinal;
}
function multi() {
function tempmulti(num1pre, num2pre) {
var parsedNums = parseNums(num1pre, num2pre, 3),
neg = [parsedNums.isNeg, parsedNums.num1.isNeg, parsedNums.num2.isNeg],
final = "",
decimals = parsedNums.decimals,
numArray = [],
num2 = parsedNums.num2,
num1 = parsedNums.num1;
if (num2.num.length == 1 && num2.num[0] == "1") return formatNums(num2.num, decimals, neg);
else if (num2.length == 1 && num2[0] == "0") return "1";
else {
final = add(num1, num1);
for (var i = "2"; isLessThan(i, num2); i = add({
num: i.split(""),
isNeg: false,
decimals: 0
}, {
num: ["1"],
isNeg: false,
decimals: 0
})) final = add(final, num1);
}
return formatNums(final, decimals, neg);
}
var permfinal, a = arguments;
if (Array.isArray(a[0])) a = a[0];
permfinal = tempmulti(a[0], a[1]);
for (var i = 2; i < a.length; i++) permfinal = tempmulti(permfinal, a[i]);
return permfinal;
}
function expo() {
function tempexpo(num1pre, num2pre) {
var parsedNums = parseNums(num1pre, num2pre, 5),
num1 = parsedNums.num1,
num2 = parsedNums.num2,
decimals = parsedNums.decimals,
decimal2 = parsedNums.num2.decimals,
neg = [parsedNums.isNeg, parsedNums.num1.isNeg, parsedNums.num2.isNeg],
numArray = [],
final = "";
if (neg[1]) num1.num.unshift("-");
if (neg[2]) num2.num.unshift("-");
if (decimal2 > 0) {
// root_of_decimal2*10(num1)**(num2*(10*decimal2))
alert("Decimal exponents aren't supported yet");
throw new TypeError("Decimal exponents aren't supported yet");
} else {
if (num2.num.length == 1 && num2.num[0] == "1") return formatNums(num2.num, decimals, false);
else if (num2.num.length == 1 && num2.num[0] == "0") return "1";
else {
final = multi(num1, num1);
for (var i = "2"; isLessThan(i, num2); i = add({
num: i.split(""),
isNeg: false,
decimals: 0
}, {
num: ["1"],
isNeg: false,
decimals: 0
})) {
final = multi(final, num1);
console.log(num1, num2, i);
}
return final;
}
//Need to fix div -> if (neg[2]) return div("1", final);
}
}
var permfinal, a = arguments;
if (Array.isArray(a[0])) a = a[0];
permfinal = tempexpo(a[0], a[1]);
for (var i = 2; i < a.length; i++) permfinal = tempexpo(permfinal, a[i]);
return permfinal;
}
console.log(expo("2", "64"));
Why is this happening? Is there a work-around?
If you saw the previous post, sorry. I've been very frustrated with this bug.
Doing the following:
var num1save = JSON.parse(JSON.stringify(num1));
var num2save = JSON.parse(JSON.stringify(num2));
sets a save variable that isn't just a reference but is instead a good copy and then doing this to set the save:
num1 = JSON.parse(JSON.stringify(num1save));
num2 = JSON.parse(JSON.stringify(num2save));
doesn't prevent the problem from happening, but prevents it from causing any issues. Appling this in a way other than in the for loop would prevent the issue from happening.
I am looking to find the passed parameter to a function
say i already have hello as function and i have a STRING as following
hello(1,'434','hello,word',"h,g",{a:'b,u', l : { "sk" : "list", bk : 'u,93' }, c : 9},true)
Then upon that regex or function i should be able to find following 6 strings
'1'
'"434"'
'"hello,world"'
'"h,g"'
'{"a":"b,u","l":{"sk":"list","bk": "u,93"},"c":9}'
'true'
As per urs question you can do it like this:
x =Hello(1,'434','hello,word',"h,g",{a:'b,u', l : { "sk" : "list", bk : 'u,93' }, c : 9},true);
function Hello() {
for (i = 0; i <arguments.length; i++) {
console.log(arguments[i])
}
}
You can take help of argument object which is an Array-like object corresponding to the arguments passed to a function.
If that's a string then you might have to escape the double quotes first to result like
var x = "hello(1,'434','hello,word',\"h,g\",{a:'b,u', l : { \"sk\" : \"list\", bk : 'u,93' }, c : 9},true)";
and then you may invoke it like
Function(x)();
and in the hello function you should iterate over the arguments object's properties like
function hello(){
Array.prototype.forEach.call(arguments, prop => console.log(prop));
}
This is my workaround. It may be error-prone, but it should be faster than the eval solutions.
var extractParameters = function(str){
var ar = [];
if(typeof str === 'string' && str.length){
var chars = str.split(','), cl = chars.length;
var pushInto = function(n){
try {
ar.push(JSON.parse(chars[n]));
} catch(er){
ar.push(undefined);
}
};
for(var di, si, eg, fg, n = 0; n < cl; n++){
eg = chars[n].charAt(0);
fg = chars[n].charAt(chars[n].length - 1);
if(eg === fg && (eg === '"' || eg === "'")){
chars[n] = "\"" + chars[n].substring(1, chars[n].length - 1) + "\"";
}
di = chars[n].indexOf('"');
si = chars[n].indexOf("'");
if(((si === -1) && (di === -1)) || (eg === fg && (eg === '"' || eg === "'")) ||
(chars[n].charAt(0) === "{" && chars[n].charAt(chars[n].length-1) === "}" && (chars[n].match(/\{/g).length === chars[n].match(/\}/g).length))){
pushInto(n);
} else if(n < (cl-1)) {
chars[n] = chars[n] + ','+ chars[n+1];
chars.splice(n+1,1);
n--;
cl--;
continue;
}
}
}
return ar;
};
fiddle : https://jsfiddle.net/jv0328tp/16/
I'm a javascript beginner doing some CodeWars.com questions. I came across this question and I'm stuck due to a "cannot read property length null" error. I've tried to look up that error and can't find what the problem is in my program.
The assignment is:
"Check to see if a string has the same amount of 'x's and 'o's. The method must return a boolean and be case insensitive. The string can contains any char."
And this is what I've written so far:
function XO(str) {
var x = "x";
var o = "o";
var numX = str.match(/x/gi).length;
var numO = str.match(/o/gi).length;
while(str.indexOf(x) > -1 || str.indexOf(o) > -1) {
if(numX == numO){
return true;
}
}
if (numX === -1 && numO === -1){
return true;
}
}
XO("xoxo");
The assignment also says that if there is neither an X or an O then the program should return true.
This will not give you that error. When there are no matches, the match function returns null and you cannot get the length of null. A few extra lines solves this issue.
function XO(str) {
var x = "x";
var o = "o";
var numX = 0;
var numO = 0;
var xMatch = str.match(/x/gi);
var oMatch = str.match(/o/gi);
if (xMatch) {
numX = xMatch.length;
}
if (oMatch) {
numO = oMatch.length;
}
while(str.indexOf(x) > -1 || str.indexOf(o) > -1) {
if(numX == numO){
return true;
} else {
return false;
}
}
if (numX === -1 && numO === -1){
return true;
} else {
return false;
}
}
console.log(XO("ddd"));
I think you are making this problem more complex than it has to be.
All you need to do is make the string lowercase(to account for case insensitive), traverse the string, and when it finds an x, add 1 to a counter, and when you find and o, decrease 1 from the counter.
If it ends at 0, you return true, else you return false. There's no need for regexes
function XO(str){
var count = 0;
str = str.toLowerCase();
for(var i = 0; i < str.length; i++){
if(str[i] === 'x') count++;
if(str[i] === 'o') count--;
}
return count === 0 ? true : false;
}
Yes you have to check the return value of match is not null before checking the length property. However
while(str.indexOf(x) > -1 || str.indexOf(o) > -1) {
if(numX == numO){
return true;
}
}
looks like an infinite loop if either string contains lower case 'x' or 'o' and there are a different number of each.
More simply:
function XO(str)
{ var matchX = str.match(/x/gi);
var matchY = str.match(/o/gi);
return (matchX && matchY) ? matchX.length == matchY.length : !matchX && !matchY;
}
I have a variable in javascript:
var myvar = "0711111111";
I bascially need to do a condition saying:
if (myvar's first character = '0') or (myvar's first character = '+') {
then ... replace the first character with 'somethingelse';
}
Please try this !
var myvar = "0711111111" , repWithChar = "x";
var firstChar = myvar.charAt(0);
if ((firstChar === "0") || (firstChar === "+")) {
console.log( myvar.replace(myvar.charAt(0), repWithChar) );
}
Output: x711111111
var myvar = "0711111111";
if(myvar[0] == "0" || myvar[0] == "+"){
myvar = myvar.substring(1);
}
or Use charAt()
if(myvar.charAt(0) == "0" || myvar.charAt(0) == "+"){
myvar = myvar.substring(1);
}
or use substring()
if(myvar.substring(0,1) == "0" || myvar.substring(0,1) == "+"){
myvar = myvar.substring(1);
}
Fiddle
var myvar = "0711111111";
if(myvar[0] == "0" || myvar[0] == "+"){
myvar[0] = "$"; // U can replace
}
var myvar = "0711111111";
if (myvar.charAt(0) == '0' || myvar.charAt(0) == '+') {
// Replace the char in pos 0 with desired char (now using '=')
myvar = myvar.replace(myvar.charAt(0), '=')
}
Output: "=711111111"
take the first character with myvar[0] and compare with the other two characters
var firstchar = myvar[0]; //or myvar.charAt(0) for ie7 and older support
if ( firstchar === '0' || firstchar === '+' ) {
// do stuff
myvar = myvar.replace( firstchar, 'X' ); // where X is the new character
}