Matching balanced parenthesis in Ruby using recursive regular expressions like perl
Yes. With oniguruma regex engine, which is built in in Ruby 1.9, and is installable on Ruby 1.8, you can do that. You name a subregex with (?<name>...)
or (?'name'...)
. Then you call a subregex with \g<name>
or \g'name'
within the same regex. So your regex translated to oniguruma regex will be:
re = %r{
(?<re>
\(
(?:
(?> [^()]+ )
|
\g<re>
)*
\)
)
}x
Also note that multi-byte string module in PHP >=5 uses oniguruma regex engine, so you will be able to do the same.
The manual for oniguruma is here.
Checking if a string has balanced parentheses
Here are descriptions of two algorithms that should accomplish the goal. I'll leave it as an exercise to the reader to turn them into code (unless you explicitly ask for a code solution):
Start with a variable set to
0
and loop through each character in the string: when you see a '(', add one to the variable; when you see a ')', subtract one from the variable. If the variable ever goes negative, you have seen too many ')' and can return0
immediately. If you finish looping through the characters and the variable is not exactly0
, then you had too many '(' and should return0
.Remove every occurrence of '()' in the string (replace with ''). Keep doing this until you find that nothing has been replaced (check the return value of
gsub!
). If the string is empty, the parentheses were matched. If the string is not empty, it was mismatched.
Balanced brackets conditional issue
The if statement if bracket == "{" or "[" or "("
needs to have a bracket == X
for each or
condition in the statement. Change:
if bracket == "{" or "[" or "("
to
if bracket == "{" or bracket == "[" or bracket == "("
...and that should work. The full code would be:
def balanced?(list_of_brackets)
if list_of_brackets.length % 2 != 0
false
else
stack = []
bracket_sets = {
'{' => '}',
'[' => ']',
'(' => ')'
}
list_of_brackets.chars do |bracket|
if bracket == "{" or bracket == "[" or bracket == "("
puts "#{bracket} is an opening bracket"
else
puts "#{bracket} is a closing bracket"
end
end
end
stack.empty?
end
puts balanced?('{}()[]')
Ruby - Regex for matching brackets?
non_delimiters = /[^(){}\[\]]*/
Paired = /\(#{non_delimiters}\)|\{#{non_delimiters}\}|\[#{non_delimiters}\]/
Delimiter = /[(){}\[\]]/
def balanced? s
s = s.dup
s.gsub!(Paired, "".freeze) while s =~ Paired
s !~ Delimiter
end
balanced?(")([]{}")
# => false
balanced?("[]")
# => true
balanced?("[()]")
# => true
balanced?("{}")
# => true
balanced?("}{")
# => false
balanced?("}[]}")
# => false
balanced?("[[]]")
# => true
Regular expression to match balanced parentheses
Regular expressions are the wrong tool for the job because you are dealing with nested structures, i.e. recursion.
But there is a simple algorithm to do this, which I described in more detail in this answer to a previous question. The gist is to write code which scans through the string keeping a counter of the open parentheses which have not yet been matched by a closing parenthesis. When that counter returns to zero, then you know you've reached the final closing parenthesis.
Simple Ragel Example that Balances Parentheses?
A general pattern using fcall/fret is like:
balanced = [^(){}\[\]] |
'(' @{ fcall balancedTokensParen; } |
'[' @{ fcall balancedTokensBracket; } |
'{' @{ fcall balancedTokensBrace; };
balancedTokensParen := balanced* ')' @{ fret; };
balancedTokensBracket := balanced* ']' @{ fret; };
balancedTokensBrace := balanced* '}' @{ fret; };
So your case could be handled as
char = [xo];
group = '(' @{ fcall group_rest; };
group_rest := (char|group)* ')' @{ fret; };
main := group;
the lexer function should contain the stack
array, and you have to manually to check the top
to ensure there isn't unclosed '(':
stack = []
%% write init;
%% write exec;
if top > 0
cs = %%{ write error; }%%
end
Search for matching parenthesis
It is not possible to do this correctly without a stack under one form or another. The way you are doing it does not cope correctly with nestings. For example it will incorrectly accept "[(])"
Detecting bad syntax in a string
[Edit: I've incorporated both of @sawa's excellent suggestions.]
One way you can do this is with a stack.
MATCH = { '['=>']', '('=>')', '{'=>'}' }
OPENING = MATCH.keys
CLOSING = MATCH.values
def check_for_match(str)
str.chars.each_with_object([]) do |c, arr|
case c
when *OPENING
arr << c
when *CLOSING
return false unless c.eql?(MATCH[arr.pop])
end
end.empty?
end
check_for_match("zx(c)abcde[z{x]}") #=> false
check_for_match("zx(c)abcde[z{x}]") #=> true
Related Topics
Find Products Matching All Categories (Rails 3.1)
How to Remove the Zone from a Datetime Value
Another Way Instead of Escaping Regex Patterns
How to Populate an Array with Random Numbers
Ruby on Rails Activerecord Scopes VS Class Methods
Rails 4: How to Upload Files with Ajax
How to Force Rails to Load All Models
Devise Not Displaying Error Messge During an Authentication Failure
Positive Lookahead Doesn't Stop at First Occurrence
(New to Rails) Rails Server Error: Cannot Load Such File -- Bootsnap/Setup (Loaderror)
Getting Current Line of Code in Ruby
Automatic Associations in Ruby on Rails Fixtures
How to Run "Bundle Exec Jekyll New ."
Ruby - Test Whether Database Connection Is Possible