module ActionView::Helpers::TextHelper

def highlight(text, phrases, options = {}, &block)

# => "ruby on rails"
highlight('ruby on rails', 'rails', sanitize: false)

# => "You searched for: rails"
highlight('You searched for: rails', 'rails') { |match| link_to(search_path(q: match, match)) }

# => "You searched for: rails"
highlight('You searched for: rails', 'rails', highlighter: '\1')

# => "You searched for: rails"
highlight('You searched for: rails', ['for', 'rails'], highlighter: '\1')

# => "You searched for: ruby, rails, dhh"
highlight('You searched for: ruby, rails, dhh', 'actionpack')

# => "You searched for: rails"
highlight('You searched for: rails', /for|rails/)

# => "You searched for: rails"
highlight('You searched for: rails', 'rails')

==== Examples

Whether to sanitize +text+ before highlighting. Defaults to true.
[+:sanitize+]

This option is ignored if a block is specified.
phrase, similar to +String#sub+. Defaults to "\1".
The highlighter string. Uses \1 as the placeholder for a
[+:highlighter+]

==== Options

return value will be inserted into the final result.
string. Each occurrence of a phrase will be passed to the block, and its
If a block is specified, it will be used instead of the highlighter

sanitized before highlighting to prevent possible XSS attacks.
expressions. The result will be marked HTML safe. By default, +text+ is
highlighter string. +phrases+ can be one or more strings or regular
Highlights occurrences of +phrases+ in +text+ by formatting them with a
def highlight(text, phrases, options = {}, &block)
  text = sanitize(text) if options.fetch(:sanitize, true)
  if text.blank? || phrases.blank?
    text || ""
  else
    patterns = Array(phrases).map { |phrase| Regexp === phrase ? phrase : Regexp.escape(phrase) }
    pattern = /(#{patterns.join("|")})/i
    highlighter = options.fetch(:highlighter, '<mark>\1</mark>') unless block
    text.scan(/<[^>]*|[^<]+/).each do |segment|
      if !segment.start_with?("<")
        if block
          segment.gsub!(pattern, &block)
        else
          segment.gsub!(pattern, highlighter)
        end
      end
    end.join
  end.html_safe
end