Skip to content

Instantly share code, notes, and snippets.

@jyutzler
Last active March 29, 2017 14:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jyutzler/49ac089f763741bff6cff2883079111a to your computer and use it in GitHub Desktop.
Save jyutzler/49ac089f763741bff6cff2883079111a to your computer and use it in GitHub Desktop.
Parsing various lat/lon coordinate inputs in JS
var tests = [
"40.6456",
"40.6456 .20",
"+40,-.20",
"+40.6456,-20",
" +40.6456 , -20. ",
"40.6456. 20.",
" 40:30:45.78 N , 11:30:45.78 s ",
" 40:30:45.78 N -111:30:45.78 ",
" 40:30:45.78 N 111:30:45.78 E ",
" 111:30:45.78 W 40:30:45.0 S ",
" 40:30:45 W , 11:30:45.78 s ",
"33:56:34.960 North, 55:23:34.09838 West",
"33°56'56.9\"N 123:39:45.346W",
"33d 56' 18.3839\" S",
"-33:45:45.3434 -133:56:34.960",
"40 34 56.45 N 19 45 34 W",
"40/34/56.45 N 19,45,34.656 W",
"40 34 N 19 45 34 e",
"40/34/56.45 N 19 W", // Is this valid? It isn't passing.
"40/34/56. sOuTh 19 45 W",
"-40/34/56.45 -19,45,34.656"
];
var dd = {
// Returns the input as WKT
parse: function(input) {
var re = /[-+]?((\d+\.\d*)|(\d*\.\d+)|(\d+))/ig;
var lat = re.exec(input)[0];
var lon = re.exec(input)[0];
return "POINT(" + lon + " " + lat + ")";
},
// Returns false if there is no issue with the input
// Returns a message string if there is a problem
test: function(input) {
return /^\s*[-+]?((\d+\.\d*)|(\d*\.\d+)|(\d+))((\s*,\s*)|(\s+))[-+]?((\d+\.\d*)|(\d*\.\d+)|(\d+))\s*$/.test(input) ?
false : "regex";
}
};
var dms = {
regex: /\s*([+-]?)(\d{1,3})[^\d](\d{1,2})[^\d](\d{1,2}\.?\d*)?\s*([news]|north|south|east|west)?(?:\s+|(?:\s*,\s*))([+-]?)(\d{1,3})[^\d](\d{1,2})[^\d](\d{1,2}\.?\d*)?\s*([news]|north|south|east|west)?\s*/i,
// Returns the input as WKT
parse: function(input) {
// Converts an input like "40:30:45.78 N" into decimal degrees
function dd(input) {
var result = +input.deg;
if (input.min) {
result += +input.min / 60.0;
}
if (input.sec) {
result += parseFloat(input.sec) / 3600.0;
}
if ((input.dir && input.dir.match(/[ws]/i)) || (input.pol && input.pol.match(/-/))) {
result *= -1.0;
}
return result;
}
var vals = this.split(input);
// We might get explicit NSEW values
var dd1 = dd(vals.c1);
var isLat1 = /.*[ns].*/i.test(vals.c1);
var dd2 = dd(vals.c2);
var isLat2 = /.*[ns].*/i.test(vals.c2);
// If we don't get explicit NSEW values, assume lat, long input
if (!(isLat1 || isLat2)) {
isLat1 = true;
}
// But of course WKT is long, lat
return "POINT(" + (isLat1 ? dd2 : dd1) + " " + (isLat1 ? dd1 : dd2) + ")";
},
// helper function that
// splits the results from a regex call into a typed object
split: function(input) {
var vals = this.regex.exec(input);
return {
c1: {
pol: vals[1],
deg: vals[2],
min: vals[3],
sec: vals[4],
dir: vals[5]
},
c2: {
pol: vals[6],
deg: vals[7],
min: vals[8],
sec: vals[9],
dir: vals[10]
}
};
},
// Returns false if there is no issue with the input
// Returns a message string if there is a problem
test: function(input) {
if (this.regex.test(input)) {
var rvalues = this.split(input);
if (rvalues.c1.dir || rvalues.c2.dir) {
if (rvalues.c1.dir && rvalues.c2.dir) {
// We need one NS value and one EW one
var ns1 = /.*[ns].*/i.test(rvalues.c1.dir);
var ns2 = /.*[ns].*/i.test(rvalues.c2.dir);
if ((ns1 || ns2) && !(ns1 && ns2)) {
return false;
} else {
return "One coordinate must be latitude and one must be longitude";
}
// Have to have both or neither
} else {
return "Coordinates must both have directions (N/S/E/W) (or neither in which case they are read as lat, long)";
}
}
return false;
}
return "regex";
}
};
var parsers = [dd, dms];
// test tests a string to see if it is a coordinate pair
// @return an object with a message or a wkt point string
function test(input) {
var parser = false;
var message;
for (let curr of parsers) {
message = curr.test(input);
if (message === "regex") {
continue;
} else {
parser = curr;
break;
}
}
if (message === "regex") {
message = "Enter a pair of coordinates (lat/long) in decimal degrees or degrees/minutes/(seconds)";
}
return message ? {"message":message} : {"wkt":parser.parse(input)};
}
for (let curr of tests) {
let status = test(curr);
console.log(curr + " => " + (status.wkt ? status.wkt : status.message));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment