input: Write a python function to search for a pattern in a string using the Boyer Moore pattern matching algorithm.
  assert boyer_moore("Hello World!", "World") == 6
  assert boyer_moore("abcdefg", "def") == 3
  assert boyer_moore("abcdefg", "xyz") == -1
output: def boyer_moore(text, pattern):
      def build_bad_character_table(pattern):
          table = {}
          for i in range(len(pattern)):
              table[pattern[i]] = i
          return table
  
      def build_good_suffix_table(pattern):
          m = len(pattern)
          table = [0] * (m + 1)
          last_prefix_position = m
  
          for i in range(m - 1, -1, -1):
              if pattern[:i+1] == pattern[m-i-1:]:
                  last_prefix_position = i + 1
              table[m - i - 1] = last_prefix_position + (m - i - 1)
  
          for i in range(m):
              len_suffix = 0
              while (len_suffix < i and
                     pattern[i - len_suffix] == pattern[m - 1 - len_suffix]):
                  len_suffix += 1
              if pattern[i - len_suffix] != pattern[m - 1 - len_suffix]:
                  table[m - 1 - len_suffix] = i - len_suffix + m
  
          return table
  
      m, n = len(pattern), len(text)
      if m == 0:
          return 0
  
      bad_char_table = build_bad_character_table(pattern)
      good_suffix_table = build_good_suffix_table(pattern)
  
      s = 0
      while s <= n - m:
          j = m - 1
  
          while j >= 0 and pattern[j] == text[s + j]:
              j -= 1
  
          if j < 0:
              return s
          else:
              bad_char_shift = j - bad_char_table.get(text[s + j], -1)
              good_suffix_shift = good_suffix_table[j + 1]
              s += max(bad_char_shift, good_suffix_shift)
  
      return -1