def parse_catalog_line(line):
    """
    This parses a line of data extracted from a molecular data file.
    It returns a dictionary with fairly obvious keys.
    For the encoding details see
    http://www.astro.uni-koeln.de/site/vorhersagen/catalog/main_catalog.shtml\
      #description
    """
    line_data = line.split()
    data = {}
    data['freq'] = float(line_data[0])          # MHz
    data['freq err'] = float(line_data[1])      # MHz
    data['str'] = pow(10,float(line_data[2]))   # S mu^2, the line strength
    data['deg free'] = int(line_data[3])        # Degrees of freedom in the
                                                # rotational partition function
                                                #(0 for atoms,
                                                # 2 for linear molecules, and
                                                # 3 for nonlinear molecules).
    data['E lower'] = float(line_data[4])       # cm^{-1}
    data['g upper'] = int(line_data[5])         # for upper state
    data['tag'] = int(line_data[6])             # molecule code
    data['qn format'] = int(line_data[7])
    q_low = []
    q_up = []
    if data['qn format'] == 999:
      # in this case, the string range [55:] has eight fields of three
      for i in range(4):
        ptr_up = 55+3*i
        ptr_low = 55+12+3*i
        q_up.append(line[ptr_up:ptr_up+3].strip())
        q_low.append(line[ptr_low:ptr_low+3].strip())
      data['q upper'] = q_up
      data['q lower'] = q_low
    else:
      # JPL catalog format; the range [55:] has twelve fields of two
      for i in range(6):
        ptr_up = 55+2*i
        ptr_low = 55+12+2*i
        q_up.append(line[ptr_up:ptr_up+2].strip())
        q_low.append(line[ptr_low:ptr_low+2].strip())
      data['q upper'] = q_up
      data['q lower'] = q_low
    return(data)