-1

So I'm trying to solve a challenge where if the perens are in the right order, I return true; else, of course, false. Code I came up with is here:

def valid_parentheses(str)
    return false if str.length % 2 == 1
        begin
            eval(str)
        rescue SyntaxError
            false
        else
            true
        end
    end
end

Works like a charm except in situations like valid_parentheses("hi(hi)()") which should returns # => true but instead returns false because the ending () are quote-unquote unnecessary and therefore raises an error.

I tried to split it out by parentheses, but:

str.split(/\(.*\))
# =>"hi"

because it deleted all the parens, and:

str.scan(/\(.*\))
#=> "(hi)()"

because it still technically starts with ( and ends with ).

How do I split that up to get "(hi)" and "()" separately?

Casimir et Hippolyte
  • 83,228
  • 5
  • 85
  • 113
Andrea McKenzie
  • 229
  • 1
  • 11
  • Could you explain clearly what you want to achieve with one or several example input strings and the corresponding expected results? If I understand well, you want to check if parenthesis are balanced, isn't it? I can say already that the method `split` isn't the way to go. And why this strange test `return false if str.length % 2 == 1`? *(note that `== 1` is useless, and instead of using the modulo, you can check the last bit)* – Casimir et Hippolyte Feb 27 '16 at 23:09

3 Answers3

0

You are close to what you want. Here is the regex I'd use if I understood correctly your question :

(\(.*?\))

\(      // match the left bracket
.*?     // match any character as FEW times as possible (lazy use of * because of the ?)
\)      // match the right bracket

Regex Demo

Indeed, thanks to the lazy mode, the search of the given character(s) will begin right after at the last consumed character.

  • X* start the search at end of the line (greedy)
  • X*? start the search right after the last consumed character (lazy)
  • X*+ is like the greedy quantifier except that it doesn't backtrack

@Anomie explain it here : Greedy vs. Reluctant vs. Possessive Quantifiers

Community
  • 1
  • 1
Cédric M.
  • 1,052
  • 3
  • 12
  • 23
0

There are a few ways to do that. One is to first remove all characters other than "(" and ")", then in a loop remove substrings "()", continuing until no more such pairs can be removed. If the string is then empty, the parens are balanced; else they are not.

def balanced_parens?(str)
  pstr = str.gsub(/[^()]/,"")
  puts "pstr=#{pstr}"
  while pstr.gsub!("()", "")
  end
  pstr.empty?
end

balanced_parens? "Now (is(the(time)to(have(fun)))fun)"
  #=> true
balanced_parens? "Now (is(the)time)to(have)fun)((fun)"
  #=> false

Here are the step-by-step's for these two strings:

str = "Now (is(the(time)to(have(fun)))fun)"
pstr = str.gsub(/[^()]/,"")
  #=> "((()(())))" 
pstr.gsub!("()", "")
  #=> "((()))" 
pstr.gsub!("()", "")
  #=> "(())" 
pstr.gsub!("()", "")
  #=> "()" 
pstr.gsub!("()", "")
  #=> "" 
pstr.gsub!("()", "")
  #=> nil 
pstr.empty?
  #=> true

str = "Now (is(the)time)to(have)fun)((fun)"
pstr = str.gsub(/[^()]/,"")
  #=> "(())())(()" 
pstr.gsub!("()", "")
  #=> "())(" 
pstr.gsub!("()", "")
  #=> ")(" 
pstr.gsub!("()", "")
  #=> nil 
pstr.empty?
  #=> false
Cary Swoveland
  • 94,081
  • 5
  • 54
  • 87
-1

Have you considered using a regular expression? Something like:

/hay/ =~ 'haystack'   #=> 0
/y/.match('haystack') #=> #<MatchData "y">

might work.

vibration
  • 45
  • 5
  • Just tried, actually. If I don't account for other characters (e.g. `/\(\)/.match(str)` ) it gives me "()", but if I do like I showed above, I still get "(hi)()". Thanks tho – Andrea McKenzie Feb 27 '16 at 22:19