Ruby - finding characters within parentheses
I have a string in Ruby. I need to iterate through the parentheses in a string.
My line:
(((MILK AND SOYA) OR NUT) AND COCONUT)
The first iteration should return:
((MILK AND SOYA) OR NUT) AND COCONUT
The second iteration should go back below:
(MILK AND SOYA) OR NUT
The third iteration should return the following text:
MILK AND SOYA
How do I do this in Ruby? Thanks in advance for your help.
source to share
gsub and regex
@DmitryCat's solution works great with your example, but it looks like you're interested in the innermost brackets first.
Therefore, you need to make sure that the characters between the parentheses are not parentheses:
str = "(((MILK AND SOYA) OR NUT) AND COCONUT)"
while str.gsub!(/\(([^\(\)]+)\)/){ p $1; ''}
end
# "MILK AND SOYA"
# " OR NUT"
# " AND COCONUT"
FROM "((MILK AND SOYA) OR (MILK AND NUT))"
output:
# "MILK AND SOYA"
# "MILK AND NUT"
# " OR "
Logic logic for a tree
With parser graph
Regexen is probably not the right fit for the job.
This parser
gem will have no problem parsing your expression:
require 'parser/current'
str = "(((MILK AND SOYA) OR NUT) AND COCONUT)"
p Parser::CurrentRuby.parse(str.gsub(/\b(and|or)\b/i){|s| s.downcase})
# s(:begin,
# s(:and,
# s(:begin,
# s(:or,
# s(:begin,
# s(:and,
# s(:const, nil, :MILK),
# s(:const, nil, :SOYA))),
# s(:const, nil, :NUT))),
# s(:const, nil, :COCONUT)))
You now have a tree: Root node method and children
. Which can be called recursively to get information about your expression.
With a gem sexp
(Thanks @Casper for this suggestion)
It looks like the sexp
gem can work as well, perhaps with a lighter syntax than parser
:
require 'sxp'
p SXP.read("(((MILK AND SOYA) OR (NUT AND SOYA)) AND COCONUT)")
# [[[:MILK, :AND, :SOYA], :OR, [:NUT, :AND, :SOYA]], :AND, :COCONUT]
Sphinx
As @Casper mentioned in the comments (thanks again!), You are trying to reinvent the wheel. If you need Rails full text search with booleans, Sphinx is a great tool. It's fast, good, reliable, and there is an adapter for Ruby / Rails: thinkingsphinx .
source to share
Use index to get the first character '(' and rindex to find the close character ')':
s = "(((MILK AND SOYA) OR NUT) AND COCONUT)"
s = s.slice(s.index('(') + 1, s.rindex(')') - 1) unless s.index('(').nil? || s.rindex(')').nil?
With this code you will get all the required string. Just call it in a loop until s is
I hope this helps
source to share