docs: def _init_header(self, string):
          """ Extracts header part from TAF/METAR string and populates header dict
  
          Args:
              TAF/METAR report string
  
          Raises:
              MalformedTAF: An error parsing the report
  
          Returns:
              Header dictionary
          """
  
          taf_header_pattern = """
              ^
              (TAF)?    # TAF header (at times missing or duplicate)
              \s*
              (?P<type> (COR|AMD|AMD\sCOR|COR\sAMD|RTD)){0,1}
  
              \s* # There may or may not be space as COR/AMD/RTD is optional
              (?P<icao_code> [A-Z]{4}) # Station ICAO code
  
              \s* # at some aerodromes does not appear
              (?P<origin_date> \d{0,2}) # at some aerodromes does not appear
              (?P<origin_hours> \d{0,2}) # at some aerodromes does not appear
              (?P<origin_minutes> \d{0,2}) # at some aerodromes does not appear
              Z? # Zulu time (UTC, that is) # at some aerodromes does not appear
  
              \s*
              (?P<valid_from_date> \d{0,2})
              (?P<valid_from_hours> \d{0,2})
              /
              (?P<valid_till_date> \d{0,2})
              (?P<valid_till_hours> \d{0,2})
          """
  
          metar_header_pattern = """
              ^
              (METAR)?    # METAR header (at times missing or duplicate)
              \s*
              (?P<icao_code> [A-Z]{4}) # Station ICAO code
  
              \s* # at some aerodromes does not appear
              (?P<origin_date> \d{0,2}) # at some aerodromes does not appear
              (?P<origin_hours> \d{0,2}) # at some aerodromes does not appear
              (?P<origin_minutes> \d{0,2}) # at some aerodromes does not appear
              Z? # Zulu time (UTC, that is) # at some aerodromes does not appear
              \s+
              (?P<type> (COR){0,1}) # Corrected # TODO: Any other values possible?
          """
  
          header_taf = re.match(taf_header_pattern, string, re.VERBOSE)
          header_metar = re.match(metar_header_pattern, string, re.VERBOSE)
  
          # The difference between a METAR and TAF header isn't that big
          # so it's likely to get both regex to match. TAF is a bit more specific so if
          # both regex match then we're most likely dealing with a TAF string.
          if header_taf:
              header_dict = header_taf.groupdict()
              header_dict['form'] = 'taf'
          elif header_metar:
              header_dict = header_metar.groupdict()
              header_dict['form'] = 'metar'
          else:
              raise MalformedTAF("No valid TAF/METAR header found")
  
          return header_dict