code: def split_using_dictionary(string, dictionary, max_key_length, single_char_parsing=False):
      
      def substring(string, i, j):
          if isinstance(string[i], tuple):
              # transform list of tuples with one element in a tuple with all elements
              return tuple([string[k][0] for k in range(i, j)])
          # just return substring
          return string[i:j]
      
      if string is None:
          return None
      if (single_char_parsing) or (max_key_length < 2):
          return [c for c in string]
      acc = []
      l = len(string)
      i = 0
      while i < l:
          found = False
          for j in range(min(i + max_key_length, l), i, -1):
              sub = substring(string, i, j)
              if sub in dictionary:
                  found = True
                  acc.append(sub)
                  i = j
                  break
          if not found:
              acc.append(string[i])
              i += 1
      return acc
docs: Return a list of (non-empty) substrings of the given string,
      where each substring is either:
      
      1. the longest string starting at the current index
         that is a key in the dictionary, or
      2. a single character that is not a key in the dictionary.
  
      If ``single_char_parsing`` is ``False``,
      parse the string one Unicode character at a time,
      that is, do not perform the greedy parsing.
  
      :param iterable string: the iterable object ("string") to split into atoms
      :param dict dictionary: the dictionary mapping atoms ("characters") to something else
      :param int max_key_length: the length of a longest key, in number of characters
      :param bool single_char_parsing: if ``True``, parse one Unicode character at a time