Skip to content

Instantly share code, notes, and snippets.

@tiagogeraldi
Created December 29, 2015 13:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tiagogeraldi/c040d9e39eb4c062ff3b to your computer and use it in GitHub Desktop.
Save tiagogeraldi/c040d9e39eb4c062ff3b to your computer and use it in GitHub Desktop.
Query searcher for string
str = "I'd like to buy a Belina instead of a Pampa"
Search.new(query: 'Belina AND Pampa').test(str) #=> true
Search.new(query: 'Belin*').test(str) #=> true
Search.new(query: '"buy a Belina"').test(str) #=> true
Search.new(query: 'Belina -Pampa').test(str) #=> false
Search.new(query: 'Belina OR Corcel').test(str) #=> true
Search.new(query: '(Belina OR Corcel) AND Pampa').test(str) #=> true
Search.new(query: '(bananas OR mangos) AND frozen').test(str) #=> false
class Search
attr_reader :query, :array_content, :string_content
def initialize(options)
@query = options[:query]
end
def test(str)
@string_content = str
@array_content = str.split(/[\s,.]+/)
matches?
end
private
def matches?
arguments = tokenize(process_parentheses(query))
result = matching_with_operators(arguments)
result ||= matching_without_operators(arguments)
result
end
def matching_with_operators(args)
if (['AND', 'OR'] & args).any?
args.each_with_index.map do |arg, i|
if arg == 'AND'
contains?(args[i-1]) && contains?(args[i+1])
elsif arg == 'OR'
contains?(args[i-1]) || contains?(args[i+1])
end
end.compact.last
end
end
def matching_without_operators(args)
args.map { |arg| contains?(arg) }.last
end
def contains?(arg)
contains = array_or_string_content(arg).include?(filter_arg(arg))
arg[0] == '-' ? !contains : contains
end
def array_or_string_content(arg)
if arg.include?('*') || arg.split.size > 1
string_content
else
array_content
end
end
def filter_arg(arg)
arg.gsub(/-|\*|\"/, '')
end
def process_parentheses(str)
while str.include?('(') do
sub_query = str[str.index('(') + 1, str.index(')') - 1]
str.gsub!("(#{sub_query})", solve_sub_query(sub_query))
end
str
end
def solve_sub_query(sub_query)
if matching_with_operators(tokenize(sub_query))
array_content.first # existent word
else
"#SDX$#CVCDF@##GD123FGDG@#1231" #nonexistent word
end
end
def tokenize(str)
str.split(/\s(?=(?:[^'"]|'[^']*'|"[^"]*")*$)/).select do |s|
s.present?
end.map do |s|
s.gsub(/(^ +)|( +$)|(^["']+)|(["']+$)/,'')
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment