This is my first attempt at the Ruby Quiz, and I'm new to the
language, so please be gentle!
First, checking validity only (I'm ignoring the contents of the
packaging, if treating {foo} as valid as well as {B}):
Brackets = {'(' => ')', '[' => ']', '{' => '}'}
@fix = ARGV.shift == "-f"
desc = gets.chomp
closers = []
desc.split(//).each do |c|
if Brackets.has_key?(c)
# Add expected corresponding bracket to a stack
closers.push(Brackets[c])
elsif Brackets.has_value?(c)
closer = closers.pop
if !closer || closer != c
abort
end
end
end
abort if closers.size > 0
puts desc
Now the fixing version (behaves like the first version unless you
specify the "-f" flag):
Brackets = {'(' => ')', '[' => ']', '{' => '}'}
# Adds missing close brackets (aborts on error unless @fail).
def fix_closings(str)
closers = []
fixed = ""
str.split(//).each do |c|
if Brackets.has_key?(c)
# Add expected corresponding bracket to a stack
closers.push(Brackets[c])
elsif Brackets.has_value?(c)
closer = closers.pop
if closer
# Append any missing closing brackets
while closer != c
abort unless @fix
fixed << closer
closer = closers.pop
end
else
abort unless @fix
end
end
fixed << c
end
# If we've hit the end of the description, make sure any leftover
# closing brackets are added
closers.reverse.each {|a| fixed << a}
fixed
end
# Reverses the description, mirroring brackets (eg "{foo]" => "[oof}").
def reverse_desc(str)
new_str = ""
str.split(//).each do |c|
if Brackets.has_key?(c)
new_str << Brackets[c]
elsif Brackets.has_value?(c)
new_str << Brackets.invert[c]
else
new_str << c
end
end
new_str.reverse
end
@fix = ARGV.shift == "-f"
desc = gets.chomp
# Add missing closing brackets, flip the description and repeat, then
flip
# it back the right way round again
fixed = reverse_desc(fix_closings(reverse_desc(fix_closings(desc))))
puts fixed
No doubt it could have been done in half the code, but it seems to
work, at least on the limited examples I've tried. I started trying
to do it with regular expressions, but as usual that made my head hurt.
Kerry