Javascript - Find opening and closing bracket positions on a string? - javascript

I'm making a calculator for a site project of mine where you can type your entire expression before resolving, for example: 2+3*4 would return 14, 22-4 would return 18, 20+5! would return 140, and so on.
And that works for simple expressions like the ones I showed, but when I add brackets the code breaks.
So a simple expression like (2+3)! that should return 120 actually returns 10 or 2+3!.
my original ideia to make even the basic 2+3! work was to separate the string in math simbols and the rest. so it would separate in this case it would separate it into 2, + and 3!; where it would find the symbol and resolve just that part. And that's why it solves 10 instead of not working.
But after trying to solve I couldn't make the code work except in a extremely specific situation, so I decided to redo the code and post this here in case someone could help me out.
This is the function that I'm currently using to prepare my string for evaluation:
function sepOperFat(){
//2+3! it's working
//1+(2-(2+2)+3)! want that to work in the end
var value = document.calculator.ans.value;
var operandoPos = ['0'];
var operandoInPos = [''];
var paraResolver = [];
for(i = 0; i <= value.length; i++){
//check if value[i] is equal to +, -, ×, ÷, * & /
if(value[i] == '+' || value[i] == '-' || value[i] == '×' || value[i] == '÷' || value[i] == '*' || value[i] == '/'){
operandoPos.push(i);
operandoInPos.push(value[i]);
}
}
paraResolver.push(value.slice(operandoPos[0], operandoPos[1]));
for(var total = 1; total <= operandoPos.length; total++){
paraResolver.push(value.slice(operandoPos[total] + 1, operandoPos[total + 1]));
}
document.calculator.ans.value = '';
for(var total = 0; total <= paraResolver.length - 2; total++){
if(paraResolver[total].includes('!')){
document.calculator.ans.value += "factorial(" + paraResolver[total] + ")";
}else{
document.calculator.ans.value += paraResolver[total];
}
document.calculator.ans.value += operandoInPos[total + 1];
}
}
document.calculator.ans.value is the name of the string where i have the expression.
operandoPos is the position on the string where a symbol is at.
operandoInPos is the symbol (I maybe could have used value.charAt(operandoPos) for that too).
paraResolver is the number that I will be solving (like 3).
factorial( is the name of my function responsible for making the number factorial.
the function doesn't have a return because I still want to solve inside the document.calculator.ans.value.
to resolve the equation I'm using document.calculator.ans.value = Function('"use strict"; return '+ document.calculator.ans.value)(); that activates when I press a button.
And yeah, that's it. I just want a function capable of knowing the difference between (2+3)! and 2+(3)! so it can return factorial(2+3) instead of (2+factorial(3)).
Thank you for your help.

Your biggest problem is going to be that order of operations says parentheses need to be evaluated first. This might mean your code has to change considerably to support whatever comes out of your parentheses parsing.
I don't think you want all of that handled for you, but an approach you can take to sorting out the parenthesis part is something like this:
function parseParentheses(input) {
let openParenCount = 0;
let myOpenParenIndex = 0;
let myEndParenIndex = 0;
const result = [];
for (let i = 0; i < input.length; i++) {
if (input[i] === '(') {
if (openParenCount === 0) {
myOpenParenIndex=i;
// checking if anything exists before this set of parentheses
if (i !== myEndParenIndex) {
result.push(input.substring(myEndParenIndex, i));
}
}
openParenCount++;
}
if (input[i] === ')') {
openParenCount--;
if (openParenCount === 0) {
myEndParenIndex=i+1;
// recurse the contents of the parentheses to search for nested ones
result.push(parseParentheses(input.substring(myOpenParenIndex+1, i)));
}
}
}
// capture anything after the last parentheses
if (input.length > myEndParenIndex) {
result.push(input.substring(myEndParenIndex, input.length));
}
return result;
}
// tests
console.log(JSON.stringify(parseParentheses('1!+20'))) // ["1!+20"]
console.log(JSON.stringify(parseParentheses('1-(2+2)!'))) // ["1-",["2+2"],"!"]
console.log(JSON.stringify(parseParentheses('(1-3)*(2+5)'))) // [["1-3"],"*",["2+5"]]
console.log(JSON.stringify(parseParentheses('1+(2-(3+4))'))) // ["1+",["2-",["3+4"]]]
this will wrap your input in an array, and essentially group anything wrapped in brackets into nested arrays.
I can further explain what's happening here, but you're not likely to want this specific code so much as the general idea of how you might approach unwrapping parenthesis.
It's worth noting, the code I've provided is barely functional and has no error handling, and will behave poorly if something like 1 - (2 + 3 or 1 - )2+3( is provided.

Related

Breakpoint Debugging forEach - JS

I'm trying to return the length of the last word in a string, I am struggling with debugging at the moment. The problem is with the forEach loop I hit a breakpoint that wont update the empty array.
function lengthOfLastWord(s) {
let spaces = [];
let space = ' ';
let spaceInd = s.indexOf(space);
while (spaceInd != -1) {
spaces.push(spaceInd);
spaceInd = s.indexOf(space, spaceInd + 1);
}
let nonSpaces = [];
let wordArray = [];
for(let i = 0; i<spaces.length; i++) {
nonSpaces.push((spaces[i + 1] - spaces[i]) - 1);
}
nonSpaces.forEach(function(number) {
if (number >= 1) {
wordArray.push(number);
}
})
let words = wordArray[wordArray.length - 1];
if ((wordArray.length === 0)) {
console.log(0);
} else {
console.log(words);
}
};
lengthOfLastWord("this is my test string");
If I ignore the breakpoint I get the correct outcome, but I can't seem to figure out why the empty wordArray wont update.
(I'm sure there is an easier way to get the result using filters and mapping but i'm wondering if there is a simple fix to my current buggy code)
Right now, your code seems to return the length of the second to last word, rather than the last. The problem does not lie in the forEach, rather it is in the way you're doing it. When you take the index of spaces in the string and calculate distance between each of them, this excludes the first and the last words, as there isn't a space at the very beginning and at the very end. As a result, the second to last word's length is logged rather than the very last.
The simple fix would be to add this line right after your while loop:
spaces.push(s.length);
This will make sure that the final word length will also be calculated in the following for loop.
As you are aware, there is a much simpler way to do this.
Here is one using split:
function lengthOfLastWord(string) {
let split = string.trim().split(" ");
return split[split.length - 1].length
}

JavaScript - If statement inside a loop issues

function rot13(str) {
var yahoo = [];
for (var i = 0; i < str.length; i++) {
if (str.charCodeAt(i) > 64 && str.charCodeAt[i] < 91){continue;}{
var cnet = str.charCodeAt(i);
yahoo.push(cnet);
} else {
var j = str.charCodeAt(i);
yahoo.push(j);
}
}
var ugh = yahoo.toString();
return ugh;
}
rot13("SERR PBQR PNZC");
Attempting to use an if else statement inside a for loop and having some issues with the else statement (Getting "Syntax error: unexpected token else"). Main goal right now is to try to manipulate the strings alphabet characters while passing the other characters through (ie. spaces, exclamation points etc.). Sure there is an easier way of doing that but really just wondering what is the issue with writing an if else statement inside a loop and where im going wrong. Appreciate the help
You've got two code bodies after your if:
if (str.charCodeAt(i) > 64 && str.charCodeAt[i] < 91)
{continue;} // actual body of the if
{ // just a random block of code
var cnet = str.charCodeAt(i);
yahoo.push(cnet);
}
The second one is not part of the if at all, because you only get one code block for the if. That's why else is "unexpected".
You are attempting to invoke a statement after you have already completed the if statement. Your if results in the continue;and then does something else before you call the else. Try to refactor the continue;. It doesn't have anything to do with the for loop:)
Attempting to use an if else statement inside a for loop and having some issues with the else statement (Getting "Syntax error: unexpected token else").
but really just wondering what is the issue with writing an if else statement inside a loop and where im going wrong
that you don't write an if..else statement, but an if statement and a code block where you try to add your else statement; and this else-statement doesn't make sense there.
your code reads like this:
//this is your condition
if (str.charCodeAt(i) > 64 && str.charCodeAt[i] < 91){
continue;
}
//and this is an anonymous code block; anonymous, because you could name it
{
var cnet = str.charCodeAt(i);
yahoo.push(cnet);
//and such code-blocks have no `else`,
//that's why you get the error,
//this else doesn't belong to the condition above
} else {
var j = str.charCodeAt(i);
yahoo.push(j);
}
your problem is the {continue;} part that changes the whole menaing of your blocks to what I've described
Sure there is an easier way of doing that
yes, you could use String#replace, and replace the letters a-m with n-z and vice versa
//a little helper
const replace = (needle, replacement) => value => String(value).replace(needle, replacement);
//the definition of `rot13` as a String replacement
const rot13 = replace(
/[a-m]|([n-z])/gi,
(char,down) => String.fromCharCode(char.charCodeAt(0) + (down? -13: 13))
);
let s = "SERR PBQR PNZC";
console.log("input: %s\noutput: %s", s, rot13(s));
explanation: match[0] always contains the whole matched string, here this is the char; and I've added a group around [n-z] so that match[1] aka. down is filled when the character is a n-z, but not if the character is a-m.
Therefore I know, if down is filled, I have to do char.charCodeAt(0) - 13 otherwise char.charCodeAt(0) + 13

Write a JavaScript function to find longest substring in a given a string without repeating characters

"Write a JavaScript function to find longest substring in a given a string without repeating characters."
Here's what I tried, but it doesn't print anything
function sort(names) {
let string = "";
let namestring = names.split("");
for(let i = 0; i < namestring.length; i++) {
for(let j = 0; j < string.length; j++) {
if(string[j] != namestring[i]) {
string = string + namestring[i];
}
}
}
return string;
}
console.log(sort("google.com"));
What's wrong?
function sort(names)
{
string="";
ss="";
namestring=names.split("");
for(j=0;j<namestring.length;j++) {
for(i=j;i<namestring.length;i++) {
if(string.includes(namestring[i]))
break;
else
string+=namestring[i];
}
if(ss.length<string.length)
ss=string;
string="";
}
return ss;
}
console.log(sort("google.com"));
It's o(n^2) complexity but try this(may be o(n^3) if contains function take o(n) complexity)
function sort(names)
{
string="";
ss="";
namestring=names.split("");
for(j=0;j<namestring.length;j++) {
for(i=j;i<namestring.length;i++) {
if(string.includes(namestring[i])) // if contains not work then
break; //use includes like in snippet
else
string+=namestring[i];
}
if(ss.length<string.length)
ss=string;
string="";
}
return ss;
}
console.log(sort("google.com"));
What are you expecting the answer to be here? Should it be "ogle.com" or "gle.com"? If the first, the below should get you there, if the latter, update the tested = name.charAt(i) in the else to tested = "".
So a few things to note, though you're more than welcome to do as you wish:
1) the function name. This isn't doing a "sort" as far as I can tell, so if this is for your use (or any reuse. Basically, anything more than a one off homework assignment), you may want to rename it to something you'd actually remember (even the example I give is probably not completely best as "pick longest substring" is non-descriptive criteria).
2) variable naming. string and namestring may mean something to you here, but considering we're trying to find the longest substring (with the no double characters) in a string, I felt it was better to have the one we're checking against (tested) and the one we're storing to return later (longest). It helps make sense as you're reading through the code as you know when you are done with a checked string (tested), you want to compare if it is greater than the current longest substring (longest) and if it is bigger, you want it to be the new longest. This will save you a ton of headache to name variables to things that'll help when designing your function as you can get it as close to requirements written down as possible without trying to do some form of substitution or worse, forgetting which variable holds what.
I don't know what you want the result to be in the event that tested length is the same as longest length. Currently I have it set to retain, if you want the most recent, update the check to >=.
Beyond that, I just iterate over the string, setting to the currently tested string. Once double characters are met, I then see if what I just generated (tested) is larger than the current longest and if it is, it is now the longest. Once I finish looping across the string, I have to do the current vs longest check/set again as otherwise, it'd make the final tested meaningless (it went outside the loop before another double character situation was hit).
function pickLongestSubstring(name) {
let tested = "";
let longest = "";
for (let i = 0; i < name.length; i++) {
if (tested.length == 0 || tested.charAt(tested.length - 1) != name.charAt(i)) {
tested += name.charAt(i);
}
else {
if (tested.length > longest.length) {
longest = tested;
tested = "";
}
}
}
if (tested.length > longest.length) {
longest = tested;
}
return longest;
}
console.log(pickLongestSubstring("google.com"))
console.log(pickLongestSubstring("example.com"))
This is a recursive loop that should get the longest string. Uses sort to determine longest string. Works, even if multiple instances of same repeat char.
function longestWithoutRepeat(testString, returnString){
var returnString = returnString || "";
for(var i = 0; i < testString.length; i++) {
if(i > 0){
if(testString[i] == testString[i-1]) {
var testStringArray = testString.split(testString[i] + testString[i-1]);
testStringArray.sort(function(firstString, nextString){ return nextString.length - firstString.length})
returnString = testStringArray[0];
longestWithoutRepeat(testStringArray[0], returnString);
}
} else {
returnString = testString
}
}
return returnString;
}
console.log(longestWithoutRepeat("oolong"));
console.log(longestWithoutRepeat("google.com"));
console.log(longestWithoutRepeat("diddlyougotoofarout"));

JavaScript: Is there a benefit in using the charCode when comparing characters?

First of all: I'm a bit into JavaScript but not much.
Today I saw these code:
if (stringToSearch[i].charCodeAt(0) === codeToSearch) {
The charCodeAt() method of String is used for to compare the current char with the searched char.
The full code of the function here:
function getOccurences (stringToSearch, charToSearch) {
var ret = 0;
var codeToSearch = 0;
var i;
stringToSearch = stringToSearch.toUpperCase();
codeToSearch = charToSearch.toUpperCase().charCodeAt(0);
for (i = 0; i < stringToSearch.length; i++) {
if (stringToSearch[i].charCodeAt(0) === codeToSearch) {
ret++;
}
}
return ret;
}
I would have compared the char directly. Without using charCodeAt().
Just ...
stringToSearch[i] === charToSeach
As far as I know the computer compares just numbers anyway. Translates the characters to their UTF-codes. Subtracts these numbers against each other and then checks if the result has become zero.
So therefore my question:
Does the usage of charCodeAt() makes any sense?
Are there a benefit to favor the direct charCode-comparison over the character-comparison.
My intuition is to say there's a performance hit when you go through type-conversion and function-calling hoops like that.
That said, you'll likely eke out more performance out of the code by delegating to the native string methods, with something like:
function countCaseInsensitiveOccurrences(haystack, char) {
haystack = haystack.toUpperCase();
char = char.toUpperCase()[0];
var count = 0, pos = -1;
while ((pos = haystack.indexOf(char, pos + 1)) !== -1) {
count++;
}
return count;
}
charCode benefits when we have to increment/decrement the characters.
eg. if we have charCode('a') in variable x, then we can increment it using x++.
But if we had saved 'a' then we cannot perform arithmetic operations.
So charCodeAt(number) is used when you need to increment/decrement the characters.

Devide numbers on countup function

I'm starting to learn javascript and I basically needed a countup that adds an x value to a number(which is 0) every 1 second. I adapted a few codes I found on the web and came up with this:
var d=0;
var delay=1000;
var y=750;
function countup() {
document.getElementById('burgers').firstChild.nodeValue=y+d;
d+=y;
setTimeout(function(){countup()},delay);
}
if(window.addEventListener){
window.addEventListener('load',countup,false);
}
else {
if(window.attachEvent){
window.attachEvent('onload',countup);
}
}
There's probably residual code there but it works as intended.
Now my next step was to divide the resultant string every 3 digits using a "," - basically 1050503 would become 1,050,503.
This is what I found and adapted from my research:
"number".match(/.{1,3}(?=(.{3})+(?!.))|.{1,3}$/g).join(",");
I just can't find a way to incorporate this code into the other. What should I use to replace the "number" part of this code?
The answer might be obvious but I've tried everything I knew without sucess.
Thanks in advance!
To use your match statement, you need to convert your number to a String.
Let's say you have 1234567.
var a = 1234567;
a = a + ""; //converts to string
alert(a.match(/.{1,3}(?=(.{3})+(?!.))|.{1,3}$/g).join(","));
If you wish, you can wrap this into a function:
function baz(a) {
a = a + "";
return a.match(/.{1,3}(?=(.{3})+(?!.))|.{1,3}$/g).join(",");
}
Usage is baz(1234); and will return a string for y our.
While I do commend you for using a pattern matching algorithm, this would probably be easier to, practically speaking, implement using a basic string parsing function, as it doesn't look anywhere as intimidating from just looking at the match statement.
function foo(bar) {
charbar = (""+bar).split(""); //convert to a String
output = "";
for(x = 0; x < charbar.length; x++) { //work backwards from end of string
i = charbar.length - 1 - x; //our index
output = charbar[i] + output; //pre-pend the character to the output
if(x%3 == 2 && i > 0) { //every 3rd, we stick in a comma, except if it is not the leftmost digit
output = ',' + output;
}
}
return output;
}
Usage is basically foo(1234); which yields 1,234.

Categories