This is my code:
function pars(str) {
var p = [str.split("(").length - 1, str.split(")").length - 1];
if (p[0] > p[1]) {
for (var i = 0; i < (p[0] - p[1]); i++) {
str += ")";
}
}
return str;
}
It adds parentheses in the end of the string if it's missing.
Examples:
"((asd)s" -> "((asd)s)"
"(((ss)123" -> "(((ss)123))"
How can I make this work for beginning parentheses aswell?
Like:
"))" -> "(())"
")123))" -> "((()123))"
This is my code:
function pars(str) {
var p = [str.split("(").length - 1, str.split(")").length - 1];
if (p[0] > p[1]) {
for (var i = 0; i < (p[0] - p[1]); i++) {
str += ")";
}
}
return str;
}
It adds parentheses in the end of the string if it's missing.
Examples:
"((asd)s" -> "((asd)s)"
"(((ss)123" -> "(((ss)123))"
How can I make this work for beginning parentheses aswell?
Like:
"))" -> "(())"
")123))" -> "((()123))"
Share
Improve this question
asked Oct 27, 2014 at 11:39
user2039981user2039981
3
-
1
Count the number of unmatched
(
and)
and add)
and(
at the end and the beginning respectively. – nhahtdh Commented Oct 27, 2014 at 11:45 - @nhahtdh Deleted my answer ")(" should bee "()()" which it didn't ty. – user2039981 Commented Oct 27, 2014 at 12:00
- Please add that test case to your question. – nhahtdh Commented Oct 27, 2014 at 12:01
6 Answers
Reset to default 5Here is a simple stack-based approach. The full JSFiddle is below as well as list of confirmed test cases.
function pars(s) {
var missedOpen = 0, stack = new Array();
for (i = 0; i < s.length; i++) {
if (s[i] == '(') {
stack.push(s[i]);
} else if (s[i] == ')') {
if (!stack.pop())
missedOpen++;
}
}
return Array(missedOpen + 1).join('(') + s + Array(stack.length + 1).join(')');
}
Confirmed Test cases:
// Target: Expected
var cases = {
'()': '()',
')(': '()()',
'(': '()',
')': '()',
'This)(is))a((test)': '((This)(is))a((test))',
'(A)': '(A)',
')A(': '()A()'
};
See the plete JSFiddle is here.
As noted by a ment, here's a version without the array at all. This should be the most efficient method. All the test cases passed.
function pars(s) {
var missedOpen = 0, missedClosed = 0;
for (i = 0; i < s.length; i++) {
if (s[i] == '(') {
missedClosed++;
} else if (s[i] == ')') {
if (missedClosed > 0)
missedClosed--;
else
missedOpen++;
}
}
return Array(missedOpen + 1).join('(') + s + Array(missedClosed + 1).join(')');
}
You need both the number of unmatched beginning parenthesis and the number of unmatched end parenthesis. Here is a rough solution:
function pars(str) {
var p = 0;
var minp = 0;
for (var i = 0; i < str.length; i++) {
if (str[i] == "(") p++;
if (str[i] == ")") {
p--;
if (p<minp) minp = p;
}
}
for (i = 0; i > minp; i--) {
str = "(" + str;
}
p = p - minp; // If we added any starting parenthesis, we need to end those as well.
for (i = 0; i < p; i++) {
str = str + ")";
}
return str;
}
This one seems to work:
function pars(str){
var pars = [].reduce.call(str, function(acc, letter){
if(letter === '(') { acc.right++;}
else if(letter === ')') {
if(acc.right) {acc.right--;}
else {acc.left++;}//no starting one
}
return acc;
}, {left: 0, right: 0}),
left = pars.left,
right = pars.right;
if(left) { str = new Array(left+1).join('(') + str;}
if(right) { str += new Array(right+1).join(')');}
return str
}
var str = ')))(((fdfd)fd)('
$("#out").html(str + " - " + pars(str))
<script src="https://ajax.googleapis./ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="out"/>
This is an extremely dirty solution (which works in Firefox for the time being due to repeat
function):
function pars(str) {
var t = str;
var n;
while ((n = t.replace(/\([^()]*\)/g, "")) != t) {
t = n;
}
var open = t.match(/\)/g);
var close = t.match(/\(/g);
return "(".repeat(open.length) + str + ")".repeat(close.length);
}
Basically, it matches all pairs of ()
, then count the number of (
and )
, and append )
and (
accordingly.
A clean solution should use a counter to count the number of opening unmatched parentheses. It will discard and count the number of unmatched )
. For the number of unmatched (
, do as per normal. It will be a one-pass solution, instead of multi-pass solution like the one above.
You can use a variation on the famous stack based bracket matching algorithm here.
The general idea is that you scan the code and push an opening parenthesis onto the stack when you see one, then when you see a closing one you pop the top value from the stack and continue. This will ensure that you have the correct balance.
(123())
// ( - push -> ['(']
// 1 - nothing
// 2 - nothing
// 3 - nothing
// ( - push -> ['(', '(']
// ) - pop -> ['(']
// ) - pop -> []
However, we want to bend the rules slightly.
- If we push a closing paren onto the stack, and the stack is empty: we need to add an opening paren to the start of the string
- If we arrive at the end of the string and there are still open parens on the stack, then we need to close them.
So the code would look something like this:
function parse(str) {
var stack = []
out = str,
idx = 0,
chr = '';
for(idx = 0; idx < str.length; idx++) {
chr = str[idx];
if(chr === '(') {
stack.push(chr);
}
else if(chr === ')') {
if(stack.length > 0) {
stack.pop();
} else {
out = '(' + out;
}
}
}
for(idx = 0; idx < stack.length; idx++) {
out = out + ')';
}
return out;
}
Bonus: Because of the iterative stack based nature of this algorithm, it will generally be faster than RegEx alternatives.
Just scan the string, counting parens. +1 for (, -1 for ). If the number goes negative, you're missing a ( at the beginning. If, when you are finished, the number is positive, then that's how many )s you need to add at the end.
var addmissingparens = function(s){
var n = 0;
Array.prototype.forEach.call(s, function(c){
if(c === '('){
n += 1;
}
if(c === ')'){
if(n === 0){
s = '(' + s;
}else{
n -= 1;
}
}
});
for(; n>0; n-=1){
s += ')';
}
return s;
};