MathCurvesSurfacesWallpaper GroupsGallerySoftwarePOV-Ray
ProgramingLinuxPerl PythonHTMLCSSJavaScriptPHPJavaLang DesignEmacsUnicode ♥

Programing: Decimalize Latitude Longitude

,

Here's a programing exercise, with solution's in emacs lisp, python, ruby.

Problem

Write a function “latitude-longitude-decimalize”.

It should take a string like this: "37°26′36.42″N 06°15′14.28″W". The return value should be a pair of numbers, like this: [37.44345 -6.25396].

Feel free to use perl, python, ruby, etc. I'll be posting a solution in emacs lisp in 2 days.

Solutions

Emacs Lisp

Here's my elisp solution:

jcs solution elisp

Source irreal.org

(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)))

Aaron Hawley, emacs calc

Aaron Hawley

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

not really qualify, but interesting anyway.

Mickey's solution, elisp calc detail

Mickey's solution Source www.masteringemacs.org

(defun hms-to-dec (hms-str)
  (let ((hms (split-string hms-str "[°′″NW ]" t)))
    (flet ((to-deg ()
                   (string-to-number
                    (calc-eval (format "deg(%s@ %s' %s\")"
                                       (pop hms) (pop hms) (pop hms))))))
      (list (to-deg) (to-deg)))))

Kurt's solution, python

Kurt Schwehr's solution in python, at Source schwehr.org.

temp place: Source pastebin.com

Python 3, Ian Kelly

Ian Kelly. . Source groups.google.com

# Python 3
import re
def latitude_longitude_decimalize(string):
    regex = r"""(\d+)\xb0(\d+)'([\d+.]+)"([NS])\s*(\d+)\xb0(\d+)'([\d+.]+)"([EW])"""
    match = re.match(regex, string)
    if not match:
        raise ValueError("Invalid input string: {0:r}".format(string))
    def decimalize(degrees, minutes, seconds, direction):
        decimal = int(degrees) + int(minutes) / 60 + float(seconds) / 3600
        if direction in 'SW':
            decimal = -decimal
        return decimal
    latitude = decimalize(*match.groups()[:4])
    longitude = decimalize(*match.groups()[4:8])
    return latitude, longitude

ruby, Jean-Sébastien Ney

port of Kurt's python code to ruby. by Jean-Sébastien Ney. Source gist.github.com

# Decimalize latitude longitude
# "37°26′36.42″N 06°15′14.28″W" --> (37.44345 -6.253966666666667)

$regex = %r{
  (?<lat_deg>\d{1,2})\D+
  (?<lat_min>\d{1,2})\D+
  (?<lat_sec>\d{1,2}(\.\d+))\D+
  (?<lat_hemi>[NS])
  \s+
  (?<lng_deg>\d{1,3})\D+
  (?<lng_min>\d{1,2})\D+
  (?<lng_sec>\d{1,2}(\.\d+))\D+
  (?<lng_hemi>[EW])
}x

def decimalize_location(location)
  if g = $regex.match(location)
    lat = g['lat_deg'].to_i + g['lat_min'].to_f/60 + g['lat_sec'].to_f/3600
    lat = -lat if g['lat_hemi'] == 'S'
    lng = g['lng_deg'].to_i + g['lng_min'].to_f/60 + g['lng_sec'].to_f/3600
    lng = -lng if g['lng_hemi'] == 'W'
    {y:lat, x:lng}
  end
end

elisp

Jorge A. Alfaro Murillo Source pastebin.com

;; Answer to Programing Problem: Decimalize Latitude Longitude.
;; Found in http://xahlee.blogspot.com/2012/04/programing-problem decimalize-latitude.html

;; it is very elisp in that it uses a regexp for splitting the
;; strings, and the fact that characters are also numbers in elisp:
;; N=78<S=83 and E=69<W=87

(defun decimalize-lat-lon (lat-lon-string)
  "Decimalize latitude longitude. Converts a string of the form \"37°26′36.42″N 06°15′14.28″W\" to a list with two numbers of the form (37.44345 -6.253966666666667)."
  (let* ((lat-strings (split-string (car (split-string lat-lon-string)) "[^0-9A-Z.]+"))
         (lon-strings (split-string (cadr (split-string lat-lon-string)) "[^0-9A-Z.]+"))
         (lat-sign (- 1 (* 2(/ (string-to-char (nth 3 lat-strings)) 83))))
         (lon-sign (- 1 (* 2(/ (string-to-char (nth 3 lon-strings)) 87))))
         (lat (* lat-sign
                 (+ (string-to-number (nth 0 lat-strings))
                    (/ (string-to-number (nth 1 lat-strings)) 60.0)
                    (/ (string-to-number (nth 2 lat-strings)) (* 60.0 60.0)))))
         (lon (* lon-sign
                 (+ (string-to-number (nth 0 lon-strings))
                    (/ (string-to-number (nth 1 lon-strings)) 60.0)
                    (/ (string-to-number (nth 2 lon-strings)) (* 60.0 60.0))))))
    (list lat lon)))

Test Data

Las Vegas
36°10′30″N 115°08′11″W
36.175  -115.136389

NYC
40°39′51″N 73°56′19″W
40.664167 -73.938611

Shanghai
31°12′0″N 121°30′0″E
31.2 121.5

London
51°30′26″N 0°7′39″W
51.507222 -0.1275

Tokyo
35°41′22.22″N 139°41′30.12″E
35.689506 139.6917

SF
37°46′45.48″N 122°25′9.12″W
37.7793 -122.4192
blog comments powered by Disqus