Check if the string is syntactically true - javascript

I am trying to solve a task with regex. Given a function with string parameter .The string contains (){}<>[] braces. I have to check if the string is syntactically true and I should also take a count of braces nesting.
This is my version (incomplete)`
const checkBraces = (str) => {
const newStr = str.replace(/[^(){}<>[\]]+/gi, '');
let answer = newStr.match(/\(+\)+|\<+\>+|\{+\}+|\[+\]+/g);
console.log(answer);
}
and this is the minimal count of tests for the function `
checkBraces("---(++++)----") == 0
checkBraces("") == 0
checkBraces("before ( middle []) after ") == 0
checkBraces(") (") == 1
checkBraces("} {") == 1
checkBraces("<( >)") == 1
checkBraces("( [ <> () ] <> )") == 0
checkBraces(" ( [)") == 1
If there is en error so the function should return 1 , else 0 .
In my function I first tried to replace all non-braces so I have a clear string. Now I can't solve this problem .

You can solve this by iterating through the string and keeping a stack of opening braces. Each time you find a closing brace, pop from the stack. The closing brace should match the thing you popped or they're not balanced. At the end the stack should be empty:
let braces = { // lookup to match closing with opening
'(':')',
'{':'}',
'<':'>',
'[':']'
}
let closing = new Set([')', '}', '>', ']']) // quick lookup of brackets
let opening = new Set(['(', '{', '<', '['])
function checkBraces(str) {
/* returns true if balanced, false if unbalanced */
let stack = []
for (l of str){
if (closing.has(l)){ // found a closing bracket
if (l !== braces[stack.pop()]) return false // does it match the last opening?
} else if(opening.has(l)) stack.push(l) // found an opening push to the stack
}
return stack.length === 0
}
console.log(checkBraces("before ( middle []) after "))
console.log(checkBraces("<( >)"))
console.log(checkBraces("( [ <> () ] <> )"))
console.log(checkBraces(" ( [)"))
console.log(checkBraces(" )"))
console.log(checkBraces(" <"))

Not using any inbuilt function except push and pop.
function check(s) {
var arr = [];
for (let i = 0; i < s.length; i++) {
if (s[i] === '{' || s[i] === '[' || s[i] === '(' || s[i] === '<' ) {
arr.push(s[i]);
} else if (s[i] === '}' || s[i] === ']' || s[i] === ')' || s[i] === '>' ) {
if ( arr[arr.length-1] === s[i] ) {
arr.pop();
} else {
return 'not balanced';
}
}
}
if(arr.length) return 'not balanced';
return 'balanced';
}
console.log(check('{781234}[3,4,5,6 ]< >( sdfhniusdf )'));
console.log(check('asssssssssss {}');
console.log(check(' as< habsdj');

Related

Following function must return true if given sequence is valid. Why this function doesn't return true for "||" sequence?

Function must return true for "()" sequence and false for "[)" sequence, so it does. But why this function doesn't return true for "||" sequence? Could you help, please?
I wrote this code, but nothing works :(
function check(s) {
const brackets = {
")": "(",
"]": "[",
"}": "{",
"|": "|",
};
const st = [];
for (let i = 0; i < s.length; i++) {
if (isClosedBracket(s[i])) {
if (brackets[s[i]].toString() !== st.pop()) {
return false;
}
} else {
st.push(s[i]);
}
}
return st.length === 0;
}
//if bracket is in this array, function returns true, so bracket is closing
function isClosedBracket(ch) {
return [")", "]", "}", "|"].indexOf(ch) > -1;
}
Well, since the pipe sequence "||" uses the same character for opening and closing, then when the first | (the opening one) will be encountered, the block of code for the closing bracket will be executed.
Your code works, but it will not operate correctly if the opening character is the same as the closing character. If you absolutely need this feature, then consider adding more checks in this particular situation.
However, the code will get much more complex since a singular | could also mean a closing bracket in an error sequence, so inputs like "(|)" will be a bit complicated to handle.
Thank you all! I solved this problem by adding another if/else block. Here is solution, if you need it =3
function check(str) {
let stack = [];
for (let i = 0; i < str.length; i++) {
if (
+str[i] === 1 ||
+str[i] === 3 ||
+str[i] === 5 ||
str[i] === "(" ||
str[i] === "[" ||
str[i] === "{"
) {
stack.push(str[i]);
} else if (
(+str[i] === 2 && stack.at(-1) === "1") ||
(+str[i] === 4 && stack.at(-1) === "3") ||
(+str[i] === 6 && stack.at(-1) === "5") ||
(str[i] === ")" && stack.at(-1) === "(") ||
(str[i] === "]" && stack.at(-1) === "[") ||
(str[i] === "}" && stack.at(-1) === "{")
) {
stack.pop();
} else if (str[i] !== stack.at(-1)) {
stack.push(str[i]);
} else {
stack.pop();
}
}
return !stack.length > 0;
}
Any ideas how to improve this code?

Valid Parentheses leetcode problem using JavaScript

I'm trying to figure out valid parentheses problem from leetcode using JavaScript and I couldn't figure out a plan on how to solve this problem.
Given a string s containing just the characters '(', ')', '{', '}', '[' and ']', determine if the input string is valid.
An input string is valid if:
Open brackets must be closed by the same type of brackets.
Open brackets must be closed in the correct order.
Every close bracket has a corresponding open bracket of the same type.
Example 1:
Input: s = "()"
Output: true
Example 2:
Input: s = "()[]{}"
Output: true
Example 3:
Input: s = "(]"
Output: false
My current thinking process is like this:
Split the string into an array (example: "{}" --> ["{","}", "[", "]", "(", ")"]
Loop through the array
Use the index of each characters to compare...?
Not sure after this...
Help please.
Here's a simple stack implementation:
const BRACKETS = [['(', ')'], ['[', ']'], ['{', '}']];
const OPEN = BRACKETS.reduce((a, [o, c]) => ({...a, [o]: c}), {});
const CLOSE = BRACKETS.reduce((a, [o, c]) => ({...a, [c]: o}), {});
const isBalanced = (s) => {
const stack = [];
for (const c of [...s]) {
if (c in OPEN) stack.push(c);
if (c in CLOSE && stack.pop() !== CLOSE[c]) return false;
}
return !stack.length;
};
console.log(isBalanced('{{[()]()}}'));
console.log(isBalanced('{[)}'));
I first create two lookup objects for opening and closing brackets. Then it's just a matter of looping over the characters, and:
if it's an opening bracket, push it onto the stack;
if it's a closing bracket, pop the last value off the stack and check whether it matches the closing bracket;
after everything is processed, check that the stack is empty.
const OPENING_BRACKETS = ['(', '[', '{']
const CLOSING_BRACKETS = [')', ']', '}']
const hasBalancedBrackets = text => !countUnmatchedBrackets(text)
function countUnmatchedBrackets(text) {
return [...text].filter(isBracket).reduce((stack, bracket) =>
isOpen(bracket) || !isMatch(stack.at(-1), bracket)
? /* push */ stack.concat(bracket)
: /* pop */ stack.slice(0, stack.length - 1), []).length
}
function isMatch(lastBracket, bracket) {
return OPENING_BRACKETS.some((openBracket, i) =>
lastBracket === openBracket &&
bracket === CLOSING_BRACKETS[i])
}
function isBracket(char) { return isOpen(char) || CLOSING_BRACKETS.includes(char) }
function isOpen(bracket) { return OPENING_BRACKETS.includes(bracket) }
[
[false, '[){'],
[true, 'a()a'],
[true, '{{[([a]a)a]a}}'],
[false, 'aa{a}a[aa(a](({[{a[[[()(([[a']
].forEach(([expected, input]) =>
console.assert(expected === hasBalancedBrackets(input), input))
Valid Parentheses In Javascript (Asked in many interviews. Simple and accepted solutions.)
Methods used here are string iteration and charAt and replace methods.
var isValid = function(s) {
let par ={'(' :')','{': '}', '[':']'};
for(let i=0;i<s.length;++i) {
if(s.charAt(i+1) && s.charAt(i+1)== par[s.charAt(i)]){
s = s.replace(s.charAt(i)+s.charAt(i+1),'');
i=i-2;
}
}
if(s.length){
console.log(false)
return false;
} else {
console.log(true)
return true;
}
};
console.log(isValid("()[]{}"))
const isValid = (s) => {
let stack = [];
const map = new Map([
['(', ')'],
['{', '}'],
['[', ']'],
]);
for (let i = 0; i < s.length; i++) {
if (s[i] == '(' || s[i] == '{' || s[i] == '[') {
stack.push(s[i]);
} else {
const last = stack.pop();
if (s[i] !== map.get(last)) {
return false;
}
}
}
return stack.length === 0;
};

Does the input string have a . or ? or ' or space?

Im writing a program that will tell you if the input string contains a period, question mark, colon or space. If it doesn't it'll return "false". If it does, it'll return all of the characters before the found punctuation. Ex. str= "grey cat", program will return "grey" because it was stopped by the space. Can I use "or" in Javascript? EDIT Im trying to do this without any built-in functions. Im not looking for an efficient way
update - now it's just printing the str. How do I get it to just print what comes before the punctuation (if any)
function find_punctuation(str){
let result = "";
for (let i = 0; i < str.length; i ++ )
if (str[i] === "." || str[i] === "?"|| str[i] === "" || str[i] === ","){
}
else result += str[i]
return result
}
console.log(find_punctuation('he. y'));
function find_punctuation(str) {
let result = "";
for (let i = 0; i < str.length; i++) {
// Determine if the current character is punctuation.
const is_punctuation = (
str[i] === "." ||
str[i] === "?" ||
str[i] === " " ||
str[i] === ","
);
if (is_punctuation) {
// If the current character is punctuation, then exit the loop.
break;
} else {
// Otherwise, keep adding to the result string.
result += str[i];
}
}
// The result string will now contain all characters until the first
// punctuation character, because the loop that added characters to
// this string was exited as soon as the first punctuation character
// was detected.
return result;
}
console.log(find_punctuation('he. y'));
console.log(find_punctuation('hell,o'));
console.log(find_punctuation('hello'));
console.log(find_punctuation('cat?erpillar'));
console.log(find_punctuation('grey cat'));
Use a regular expression:
function find_punctuation(str) {
let result = str.match(/^(.*?)[.?: ]/);
if (result) {
return result[1];
} else {
return false;
}
}
console.log(find_punctuation('he.y'));
console.log(find_punctuation('hey'));
Try this:
function find_punctuation(str){
let result = "";
for (let i = 0; i < str.length; i ++ )
if (str[i] === "." || str[i] === "?" || str[i] === " ") break
else result += str[i]
return result
}
console.log(find_punctuation('he.y'));

How to write a function that recognises unbalanced brackets

I am trying to write a function that checks if a syntax is correct or not. If it is correct it returns 'ok' else it returns the index of the error. So far my code works if it is correct, if the error is at the first index or last index. Finding errors inbetween is what i am finding difficult. Here is my code.
function syntaxError(syntax) {
let arr = syntax.split('').join()
let arr1 = [];
let arr2 = [];
let result;
//Error if the first index contain a closing braces
if (arr[0] === '>' || arr[0] === ']' || arr[0] === '}' || arr[0] === ')') {
result = 0
};
if (arr === "") {
result = 'ok'
};
//Error if its just a single brace
if (arr.length === 1) {
result = 0
};
//Error if the last index contain an opening braces
if (arr.slice(-1) === '<' || arr.slice(-1) === '[' || arr.slice(-1) === '{' || arr.slice(-1) === '(') {
result = indexOf(arr.slice(-1))
};
let char = arr[i];
if (char == '[' || char == '{' || char == '<' || char == '(') {
arr1.push(char)
} else {
arr2.push(char);
}
if (arr1.length === 0 || arr2.length === 0) {
result = 0
}
if (arr1.length === arr2.length) {
result = 'ok'
}
return result
}
The example below should return 95
('[[[[[[[[[[[[[[]]]]]]]]<<<<<<<<<<<>>>>>>>>>>>]]]]]]'+'[[[[[[[[[[[[[[]]]]]]]
<<<<<<<<<<<>>>>>>>>>>>]}]]]]' + '>')
You could take a an array for the index of each opening character and pop this if the related closing character is found.
If finished and the stack has no item, the syntax is ok, otherwise return an index or the index of the last pushed opening character.
Example:
code comment
----------- ---------------------------
[][[[]][][]
[] balanced
[ error, this returns later 2
[[]] balanced
[] balanced
[] balanced
finally a missing ]
function syntaxError(syntax) {
const
isOpening = c => /[<[{(]/.test(c),
isClosing = c => /[>\]})]/.test(c),
open = { '>': '<', ']': '[', '}': '{', ')': '(' };
var stack = [],
index,
finished = Array
.from(syntax)
.every((c, i) => {
var temp = stack[stack.length - 1];
if (isOpening(c)) {
if (temp && temp.c === c) {
temp.indices.push(i);
} else {
stack.push({ c, indices: [i] });
}
return true;
}
if (isClosing(c)) {
if (temp && temp.c === open[c]) {
temp.indices.pop();
if (!temp.indices.length) stack.pop();
} else {
index = stack.length ? stack.pop().indices.pop() : i;
return false;
}
}
return true;
});
return finished && !stack.length
? 'ok'
: index === undefined
? stack.pop().indices.pop()
: index;
}
console.log(syntaxError('[][][[{}]]')); // ok
console.log(syntaxError(')'));
// 0
console.log(syntaxError('[][][[{<}]]'));
// 01234567
console.log(syntaxError('[][[[]][][]'));
// 012
console.log(syntaxError('[[[[[[[[[[[[[[]]]]]]]]<<<<<<<<<<<>>>>>>>>>>>]]]]]]'+'[[[[[[[[[[[[[[]]]]]]]<<<<<<<<<<<>>>>>>>>>>>]}]]]]' + '>'));
An algorithm for doing this is, find an opening symbol, push it to a stack (or array, whatever). Find another opening symbol, push it to a stack. Find a closing symbol that matches the top of the stack, pop the opening symbol off the stack. Find a closing symbol that doesn't match the top of the stack, you found an error. Find a closing symbol and there's nothing on the stack, you found an error. Get to the end and still have symbols on the stack, you found an error.

Check if quotes and parentheses are balanced

There are multiple solutions to how to check if parentheses are balanced, but I haven't found a single one that would be checking both for balanced quotes and parentheses.
I have been unsuccessfully trying to adapt this solution (codereview - balanced parentheses) to be able to check if the quotes and parentheses are balanced.
For example this should be unbalanced ("back-to-school)"
Original code:
function parenthesesAreBalanced(string) {
var parentheses = "[]{}()",
stack = [],
i, character, bracePosition;
for(i = 0; character = string[i]; i++) {
bracePosition = parentheses.indexOf(character);
if(bracePosition === -1) {
continue;
}
if(bracePosition % 2 === 0) {
stack.push(bracePosition + 1); // push next expected brace position
} else {
if(stack.length === 0 || stack.pop() !== bracePosition) {
return false;
}
}
}
return stack.length === 0;
}
My code - mostly similar - but added an unbalanced quotes check.
function areQuotesAndParenthesesBalanced(s: string): boolean {
const parens = '[]{}()',
parensStack = [];
let index, char, numOfQuotes = 0;
for (index = 0; char = s[index++];){
const bracePosition = parens.indexOf(char);
let braceType;
if (bracePosition === -1 && char !== '"')
continue;
braceType = bracePosition % 2 ? 'closed' : 'open';
//check for double quotes mixed with parentheses
if(char === '"'){
const lastInStack = parensStack[parensStack.length - 1];
numOfQuotes++;
if(lastInStack === '"'){
numOfQuotes--;
parensStack.pop();
}else if(numOfQuotes > 0 && lastInStack !== '"'){
return false;
}else{
parensStack.push('"');
}
}
if (braceType === 'closed') {
if (!parensStack.length || parens.indexOf(parensStack.pop()) != bracePosition - 1)
return false;
} else {
parensStack.push(char);
}
}
//If anything is left on the stack <- not balanced
return !parensStack.length;
}
It is quite tricky for me to determine what's the best approach. With parentheses, you always know when one is open or closed, with quotes, not so much.
function tokensAreBalanced(string) {
var asymmetricTokens = "[]{}()",
symmetricTokens = '"',
stack = [],
i, character, tokenPosition;
for(i = 0; character = string[i]; i++) {
tokenPosition = asymmetricTokens.indexOf(character);
if(tokenPosition >= 0) {
if(tokenPosition % 2 === 0) {
stack.push(asymmetricTokens[tokenPosition + 1]); // push next expected token
} else if(stack.length === 0 || stack.pop() !== character) {
return false;
}
} else {
if(symmetricTokens.includes(character)) {
if(stack.length > 0 && stack[stack.length - 1] === character) {
stack.pop();
} else {
stack.push(character);
}
}
}
}
return stack.length === 0;
}
console.log('("back-to-school)"', tokensAreBalanced('("back-to-school)"'));
console.log('("back-to-school)', tokensAreBalanced('("back-to-school)'));
console.log('("back-to-school")', tokensAreBalanced('("back-to-school")'));
console.log('(ele AND car) OR ("ele car)")', tokensAreBalanced('(ele AND car) OR ("ele car)")'));
This performs a check for push() or pop() of " in 2 ways.
If stack is empty or last character in stack does not equal ", then insert this " into stack.
If stack is not empty and last character in stack is equal to ", then pop() the " in stack itself. This is done because I do a form of greedy matching here since a " for already stack " means expression inside "..." was evaluated. So, we are safe to match these 2 " and proceed with the next.
Works well, but let me know if it fails for any case.
function areQuotesAndParenthesesBalanced(s){
var pairs = {
'}':'{',
']':'[',
')':'(',
};
var stack = [];
for(var i = 0;i < s.length;++i){
switch(s.charAt(i)){
case '[': case '{':case '(':
stack.push(s.charAt(i));
break;
case ']': case '}':case ')':
if(isStackEmpty(stack) || peek(stack) !== pairs[s.charAt(i)]) return false;
stack.pop();
break;
case '"':
if(isStackEmpty(stack) || peek(stack) !== s.charAt(i)){
stack.push(s.charAt(i));
}else{
stack.pop();
}
}
}
return isStackEmpty(stack);
}
function isStackEmpty(s){
return s.length === 0;
}
function peek(s){
return s[s.length-1];
}
var tests = {
'("back-to-school")':true,
'"(back-to-school)"':true,
'("back-to-school)"':false,
'("back-to-school)':false,
'"["["["[]"]"]"]"':true,
'"["]""':false,
'"[]"""':true,
'""""':true,
'""':true,
'"':false,
'""[("")]""':true,
'""[("")]':true,
'"["["["[]"]"[""]]"]':false,
'"[]"[({})]""':true,
'"[{}"]':false
};
for(var each_test in tests){
var res = areQuotesAndParenthesesBalanced(each_test);
console.log(each_test + " --> " + (res === tests[each_test] ? "ok" : "not ok") + " , expected : " + tests[each_test]);
}
OUTPUT
("back-to-school") --> ok , expected : true
"(back-to-school)" --> ok , expected : true
("back-to-school)" --> ok , expected : false
("back-to-school) --> ok , expected : false
"["["["[]"]"]"]" --> ok , expected : true
"["]"" --> ok , expected : false
"[]""" --> ok , expected : true
"""" --> ok , expected : true
"" --> ok , expected : true
" --> ok , expected : false
""[("")]"" --> ok , expected : true
""[("")] --> ok , expected : true
"["["["[]"]"[""]]"] --> ok , expected : false
"[]"[({})]"" --> ok , expected : true
"[{}"] --> ok , expected : false
You could try putting an ordered tuple on the stack and checking based off of that.
[(,"],
[",)],
[(,"],
[",)]
== ("")("") example of a balanced stack.
[",(],
[",(],
[),"],
[),"]
== "("()")" another balanced stack
[(,"],
[),"]
== (")" trivial unbalanced stack
[(,)] <- trivial item, can ignore in implementation
[","] <- trivial item, can ignore in implementation
[",(],
[),(],
[),"]
== "()()" balanced stack
I'm too tired to actually implement this, but hopefully it gave you some ideas and illustrative examples, I'll revisit it after I get some sleep.
I would suggest simplifying the input by removing all quoted substrings. Quotes behave differently because parentheses inside quotes are not treated specially, but as normal characters. By first removing each quoted part, this "problem" is resolved from the start. Also irrelevant characters (that are not parentheses nor quotes) can be removed as well. That way we are only left with a string that has parentheses and possibly a single occurrence of a quote. The latter would immediately make the input invalid.
Here is code similar to #nice_dev's answer, with that manipulation implemented and with pairs inversed; it also deals with apostrophe as alternative delimiter:
function areQuotesAndParenthesesBalanced(s) {
const pairs = {
'{':'}',
'[':']',
'(':')',
};
const stack = [""]; // Dummy
for (const token of s.replace(/"[^"]*"|'[^']*'|[^"'{}()[\]]+/g, "")) {
if (token in pairs) {
stack.push(pairs[token]);
} else {
if (stack.at(-1) !== token) return false;
stack.pop();
}
}
return stack.length == 1; // Empty
}
// Same tests as in the answer of #nice_dev:
const tests = {
'("back-to-school")': true,
'"(back-to-school)"': true,
'("back-to-school)"': false,
'("back-to-school)': false,
'"["["["[]"]"]"]"': true,
'"["]""': false,
'"[]"""': true,
'""""': true,
'""': true,
'"': false,
'""[("")]""': true,
'""[("")]': true,
'"["["["[]"]"[""]]"]': false,
'"[]"[({})]""': true,
'"[{}"]': false
};
for (const each_test in tests){
const res = areQuotesAndParenthesesBalanced(each_test);
console.log(`${each_test} --> ${res === tests[each_test] ? "ok" : "not ok"}, expected: ${tests[each_test]}`);
}
A simple approaching way might be like this for only first braces:
function Search(str) {
const onlyBrackets = str.replace(/[a-zA-Z]/g, "");
const left = onlyBrackets.replace(/[)]/g, "");
const right = onlyBrackets.replace(/[(]/g, "");
str = left.length === right.length ? 1 : 0
return str
}
console.log(Search("(coder)(byte))")) // 0
console.log(Search("(c(oder))b(yte)")) // 1
function isParenthesisBalanced(_str) {
var parenMap = {'{':'}', '[':']', '(':')'};
var parenStack =[];
for(var i=0;i<_str.length; i++) {
if(_str[i] in parenMap) {
parenStack.push(_str[i]);
} else if(Object.values(parenMap).indexOf(_str[i]) != -1) {
if(parenMap[parenStack.pop()] != _str[i]) return false;
}
}
return true;
}

Categories