simple way to turn "foo and bar" to "+foo +bar"

Discussion in 'Ruby' started by Max Williams, Dec 14, 2007.

  1. Max Williams

    Max Williams Guest

    I want to add a slightly hacky feature into my boolean mysql search
    which lets users write 'foo and bar', which is then translated into
    '+foo +bar' (ie both 'foo' and 'bar' must be present) before being
    passed to the search. Similarly, "foo and bar and snafu" should be
    translated into "+foo +bar +snafu".

    I'm sure there must be a simple way to do this but i'm new to ruby and
    have got bogged down in loads of nested ifs and exceptions already.

    Can anyone help with an elegant solution?

    Max Williams, Dec 14, 2007
    1. Advertisements

  2. Max Williams

    Phrogz Guest

    I feel like there's a more elegant one-pass regexp, but I haven't the
    time to think much on it. So:

    phrases = [
    "foo or bar",
    "foo and bar",
    "foo and bar and snafu"

    phrases.each{ |phrase|
    result = phrase.dup
    :go while result.gsub!( /\+?(\S+)\s*and\s*(\S+)/, '+\\1 +\\2' )
    puts "#{phrase.inspect} -> #{result.inspect}"

    #=> "foo" -> "foo"
    #=> "foo or bar" -> "foo or bar"
    #=> "foo and bar" -> "+foo +bar"
    #=> "foo and bar and snafu" -> "+foo +bar +snafu"
    Phrogz, Dec 14, 2007
    1. Advertisements

  3. Hi max,

    How about...

    irb(main):001:0> "foo and bar".sub(/(foo) and (bar)/, "+#{$1} +#{$2}")
    => "+foo +bar"
    irb(main):002:0> "foo and bar".sub(/(foo) and (bar)/, '+\1 +\2')
    => "+foo +bar"
    irb(main):003:0> "foo and bar and snafu".sub(/(foo) and (bar) and
    (snafu)/, '+\1 +\2 +\3')
    => "+foo +bar +snafu"


    irb(main):004:0> "foo and bar and snafu".gsub(/(\w+)\s+and/,
    '+\1').sub(/(\w+)$/, '+\1')
    => "+foo +bar +snafu"
    John Pywtorak, Dec 14, 2007
  4. Max Williams

    MenTaLguY Guest

    query = "foo and bar and baz"
    nil while query.sub!(/\+*(\w+)\s+and\s+(\w+)/, '+\1 +\2')
    puts query

    MenTaLguY, Dec 14, 2007
  5. "foo and bar and baz".split(/\s+and\s+/i).map{|s| "+#{s}"}.join(' ')
    Rolando Abarca, Dec 14, 2007
  6. Max Williams

    MenTaLguY Guest

    I think this one is best.

    MenTaLguY, Dec 14, 2007
  7. Max Williams

    James Moore Guest

    Do you need to worry about phrases?

    Something like:

    require 'pp'
    f = "foo and bar AND north dakota"
    result = f.split(/\s+and\s+/i).inject('') {|memo, obj| memo +
    "+(#{obj}) "}.strip
    pp result

    => "+(foo) +(bar) +(north dakota)"
    James Moore, Dec 14, 2007
  8. Max Williams

    Phrogz Guest

    It's elegant, but it assumes that the search phrase always has "and".
    Although not originally specified either way, that seems like an
    unlikely assumption. But then, I don't know the problem domain.
    Phrogz, Dec 14, 2007
  9. I could not resist, so a slight mod ;-)

    "+" << "foo and bar and baz".split(/\s+and\s+/i).join(' +')

    irb(main):001:0> "+" << "foo and bar and baz".split(/\s+and\s+/i).join(' +')
    => "+foo +bar +baz"

    Johnny P
    John Pywtorak, Dec 14, 2007
  10. [Note: parts of this message were removed to make it a legal post.]

    just pass in the delimeter...

    and_str = "foo and bar AND baz"
    pipe_str = "foo|bar| baz"

    def translate(str, del)
    str.split(/\s*#{del}\s*/i).map{|s| "+#{s}"}.join(' ')

    puts translate(and_str, 'and')
    puts translate(pipe_str, '\|')

    Mike McKinney, Dec 14, 2007
  11. Max Williams

    Max Williams Guest

    Awesome, thanks a lot everyone!

    Max Williams, Dec 15, 2007
    1. Advertisements

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.