Decimalizing Latitude and Longitude

Xah Lee has reintroduced a challenge from last year. Given a string of latitude/longitude is degrees, minutes, seconds, write a function that returns them as signed decimal numbers. That is,

"37°26′36.42″N 06°15′14.28″W" → (37.44345 -6.253966666666667)

I remember looking at this challenge last year and thinking it wasn't very interesting but when I started thinking about it this time, I realized that there are a couple of twists that do make it interesting.

Here's my solution in Elisp:

(require 'cl)

(defun decimalize-lat-lon (lat-lon)
  "Decimalize latitude longitude
\"37°26′36.42″N 06°15′14.28″W\" --> (37.44345 -6.253966666666667)"
  (let (result)
    (dolist (ll (split-string lat-lon " +"))
      (destructuring-bind (deg min sec dir)
          (split-string ll "[°′″]")
        (if (string= "" dir) (error "malformed lat-lon %s" ll))
        (let ((factor (if (member dir '("S" "W")) -1 1)))
          (push (* factor (+ (string-to-number deg)
                             (/ (string-to-number min) 60.0)
                             (/ (string-to-number sec) 3600.0))) result))))
    (reverse result)))

Elisp purists might complain about my using dolist, destructuring-bind, and push from the Common Lisp package but they're convenient and don't do anything that can't be done a bit more verbosely in pure Emacs Lisp. The real workhorse in this function is the Elisp split-string function. It gets used twice: once to split the original string into latitude and longitude and once to break the latitude and longitude into their constituent parts.

The check on whether dir is the empty string really checks for any missing constituents and is just a sanity check. I didn't bother rounding the numbers to any particular number of decimal places or making the function a command. Either of those are easily done if the user needs them.

Update: Mickey over at Mastering Emacs and Aaron Hawley in the comments give nice solutions using Emacs calc. Mickey's post shows off some of the great features of calc so be sure to take a look.

This entry was posted in Programming and tagged , . Bookmark the permalink.
  • Sam

    I love your blog, and sometimes I wish i could study your code right away. Would you consider for the future to use to share your code?
    As an example, I pasted your code here:

    I like the syntax highlighting, end especially the paren highlighting.
    In case it was not proper for me to do that, I apologize in advance.

  • Aaron Hawley

    Hi, I'm the Emacs Lisp purist and I'm here to say that you didn't even use dolist from the CL package correctly. I don't know how we got to this point where *I* am making such corrections. Glad to see the require 'cl, though.

    I'm really here to suggest the Calc alternative.

    C-x * * [37@26'36.6",_6@15'14.28"] m d V M c d

    This turns on Calculator Mode, enters a vector of the two values, puts Calc in degrees mode, then maps the degree conversion operation over the vector. To go from decimal back to minutes and seconds,

    V M c h