Here's a programing exercise, with solution's in emacs lisp, python, ruby.
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.
Here's my elisp solution:
(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)))
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 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 Schwehr's solution in python, at Source schwehr.org.
temp place: Source pastebin.com
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
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
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)))
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