Word find with Ruby regex

91 views Asked by At

I can't find a word in line with the line started special word. For example;

Mike likes banana, kiwi and grapes.
Mary likes banana, apple and watermelon.

I made a mistake in Mary's favorite fruit. I want to change banana to orange. But how can find banana only starting with Mary line. I need ruby regex because of I am using it in chef cookbook.

Before;
Mike likes banana, kiwi and grapes.
Mary likes banana, apple and watermelon.

After;
Mike likes banana, kiwi and grapes.
Mary likes orange, apple and watermelon.

Best Regards
Hasan

2

There are 2 answers

1
Cary Swoveland On BEST ANSWER

We may construct the method

def sub_word(str, person, word, replacement)
  str.sub(/^(?=.*\b#{person}\b).*\K\b#{word}\b/, replacement)
end

I will display several examples for which the first line of the string (str) and last three arguments are fixed, namely

f           = "Mike likes banana, kiwi and grapes.\n"
person      = "Mary"
word        = "banana"
replacement = "orange"

It is convenient to write

args        = ["Mary", "banana", "orange"]

The only thing that changes in the examples is the second line of the string, (containing "Mary").

The examples considered are as follows.

sub_word(f + "Mary likes banana, apple and melon.", *args)
  #=> "Mike likes banana, kiwi and grapes.\nMary likes orange, apple and melon."
sub_word(f + "Mary likes apple, banana and melon.", *args)
  #=> "Mike likes banana, kiwi and grapes.\nMary likes apple, orange and melon."
sub_word(f + "Yes, Mary is fond of apple, banana and melon.", *args)
  #=> "Mike likes banana, kiwi and grapes.\nYes, Mary is fond of apple, orange and melon."
sub_word(f + "Apple, banana and melon are liked by Mary.", *args)
  #=> "Mike likes banana, kiwi and grapes.\nApple, orange and melon are liked by Mary."
sub_word(f + "Mary likes pear, apple and melon.", *args)
  #=> "Mike likes banana, kiwi and grapes.\nMary likes pear, apple and melon."
sub_word(f + "Maryann likes banana, apple and melon.", *args)
  #=> "Mike likes banana, kiwi and grapes.\nMaryann likes banana, apple and melon."
sub_word(f + "Mary likes bananas, apple and melon.", *args)
  #=> "Mike likes banana, kiwi and grapes.\nMary likes bananas, apple and melon."

In all examples the regular expression used by String#sub evaluates to the following.

/^(?=.*\b#{person}\b).*\K\b#{word}\b/
  #=> /^(?=.*\bMary\b).*\K\bbanana\b/

The elements of the expression are as follows.

^            match the beginning of a line
(?=          begin a positive lookahead
  .*         match zero or more characters other than line terminators,
             as many as possible
  \bMary\b   match 'Mary' with word boundaries before and after
)            end positive lookahead
.*           match zero or more characters other than line terminators,
             as many as possible
\K           reset the starting point of the reported match and exclude
             any previously consumed characters in the final match
\bbanana\b   match 'banana' with word boundaries before and after

Note that the positive lookahead asserts that the string "Mary" is somewhere in the line.

0
Rajagopalan On

You could use positive lookbehind like shown below

Input

a = "Mike likes banana, kiwi and grapes.
Mary likes banana, apple and watermelon."

Output

p a.gsub(/(?<=Mary .\*\s)banana/,"orange")
#=>"Mike likes banana, kiwi and grapes.
#=> Mary likes orange, apple and watermelon."

Or without using regular expression

str = "Mike likes banana, kiwi and grapes. Mary likes banana, apple and watermelon."

"Mike likes banana, kiwi and grapes. Mary likes banana, apple and watermelon."

str = str
        .lines
        .map(&:strip)
        .map { |line| line.start_with?('Mary') ? line.gsub('banana', 'Orange') : line }
        .join("\n")

p str

output

"Mike likes banana, kiwi and grapes.
Mary likes Orange, apple and watermelon."