code: def phmsdms(hmsdms):
      units = None
      sign = None
      pattern1 = re.compile(r"([-+]?[0-9]*\.?[0-9]+[^0-9\-+]*)")
      pattern2 = re.compile(r"([-+]?[0-9]*\.?[0-9]+)")
      hmsdms = hmsdms.lower()
      hdlist = pattern1.findall(hmsdms)
      parts = [None, None, None]
      def _fill_right_not_none():
          rp = reversed(parts)
          for i, j in enumerate(rp):
              if j is not None:
                  break
          if i == 0:
              raise ValueError("Invalid string.")
          elif i == 1:
              parts[2] = v
          elif i == 2:
              if parts[0] is None:
                  parts[0] = v
              else:
                  parts[1] = v
      for valun in hdlist:
          try:
              v = float(valun)
              _fill_right_not_none()
          except ValueError:
              if "hh" in valun or "h" in valun:
                  m = pattern2.search(valun)
                  parts[0] = float(valun[m.start():m.end()])
                  units = "hours"
              if "dd" in valun or "d" in valun:
                  m = pattern2.search(valun)
                  parts[0] = float(valun[m.start():m.end()])
                  units = "degrees"
              if "mm" in valun or "m" in valun:
                  m = pattern2.search(valun)
                  parts[1] = float(valun[m.start():m.end()])
              if "ss" in valun or "s" in valun:
                  m = pattern2.search(valun)
                  parts[2] = float(valun[m.start():m.end()])
              if "'" in valun:
                  m = pattern2.search(valun)
                  parts[1] = float(valun[m.start():m.end()])
              if '"' in valun:
                  m = pattern2.search(valun)
                  parts[2] = float(valun[m.start():m.end()])
              if ":" in valun:
                  v = valun.replace(":", "")
                  v = float(v)
                  _fill_right_not_none()
          if not units:
              units = "degrees"
      for i in parts:
          if i and i < 0.0:
              if sign is None:
                  sign = -1
              else:
                  raise ValueError("Only one number can be negative.")
      if sign is None:
          sign = 1
      vals = [abs(i) if i is not None else 0.0 for i in parts]
      return dict(sign=sign, units=units, vals=vals, parts=parts)