我的 GPS 信息以以下形式呈现:
北纬 36°57'9" 西经 110°4'21"
我可以使用 Chris Veness 的 javascript 函数将度、分和秒转换为数字度数,但首先需要将 GPS 信息解析为单独的纬度和经度字符串(带有 NSEW 后缀)。我已阅读 stackoverflow 上的相关帖子,但我不是正则表达式专家(也不是程序员),需要一些解析功能的帮助。将此字符串解析为纬度和经度以便在转换函数中使用的最佳方法是什么?
所有这一切的结果将是一个 Web 链接,单击该链接即可查看位置的 Google 地图表示。
function ParseDMS(input) {
var parts = input.split(/[^\d\w]+/);
var lat = ConvertDMSToDD(parts[0], parts[1], parts[2], parts[3]);
var lng = ConvertDMSToDD(parts[4], parts[5], parts[6], parts[7]);
}
以下将把您的 DMS 转换为 DD
function ConvertDMSToDD(degrees, minutes, seconds, direction) {
var dd = degrees + minutes/60 + seconds/(60*60);
if (direction == "S" || direction == "W") {
dd = dd * -1;
} // Don't do anything for N or E
return dd;
}
因此您的输入将产生以下结果:
36°57'9" N = 36.9525000
110°4'21" W = -110.0725000
十进制坐标可以输入谷歌地图以通过
GLatLng(lat, lng)
(Google Maps API)获取点
function ParseDMS(input) {
var parts = input.split(/[^\d\w\.]+/);
var lat = ConvertDMSToDD(parts[0], parts[2], parts[3], parts[4]);
var lng = ConvertDMSToDD(parts[5], parts[7], parts[8], parts[9]);
return {
Latitude : lat,
Longitude: lng,
Position : lat + ',' + lng
}
}
function ConvertDMSToDD(degrees, minutes, seconds, direction) {
var dd = Number(degrees) + Number(minutes)/60 + Number(seconds)/(60*60);
if (direction == "S" || direction == "W") {
dd = dd * -1;
} // Don't do anything for N or E
return dd;
}
function ParseDMS(input) {
var parts = input.split(/[^\d\w\.]+/);
var lat = ConvertDMSToDD(parts[0], parts[1], parts[2], parts[3]);
var lng = ConvertDMSToDD(parts[4], parts[5], parts[6], parts[7]);
}
以下将把您的 DMS 转换为 DD
function ConvertDMSToDD(degrees, minutes, seconds, direction) {
var dd = Number(degrees) + Number(minutes)/60 + Number(seconds)/(60*60);
if (direction == "S" || direction == "W") {
dd = dd * -1;
} // Don't do anything for N or E
return dd;
}
function parse_gps( input ) {
if( input.indexOf( 'N' ) == -1 && input.indexOf( 'S' ) == -1 &&
input.indexOf( 'W' ) == -1 && input.indexOf( 'E' ) == -1 ) {
return input.split(',');
}
var parts = input.split(/[°'"]+/).join(' ').split(/[^\w\S]+/);
var directions = [];
var coords = [];
var dd = 0;
var pow = 0;
for( i in parts ) {
// we end on a direction
if( isNaN( parts[i] ) ) {
var _float = parseFloat( parts[i] );
var direction = parts[i];
if( !isNaN(_float ) ) {
dd += ( _float / Math.pow( 60, pow++ ) );
direction = parts[i].replace( _float, '' );
}
direction = direction[0];
if( direction == 'S' || direction == 'W' )
dd *= -1;
directions[ directions.length ] = direction;
coords[ coords.length ] = dd;
dd = pow = 0;
} else {
dd += ( parseFloat(parts[i]) / Math.pow( 60, pow++ ) );
}
}
if( directions[0] == 'W' || directions[0] == 'E' ) {
var tmp = coords[0];
coords[0] = coords[1];
coords[1] = tmp;
}
return coords;
}
此函数不处理所有类型的纬度/经度类型,但它处理以下格式:
-31,2222,21.99999
-31 13 13 13.75S, -31 13 13 13.75W
-31 13 13 13.75S -31 13 13 13.75W
-31 13 13 13.75W -31 13.75S
36°57'9" N 110°4'21" W
110°4'21" W 36°57'9"N
这就是我所需要的。
function ConvertDMSToDD(days, minutes, seconds, direction) {
var dd = days + (minutes/60) + seconds/(60*60);
dd = parseFloat(dd);
if (direction == "S" || direction == "W") {
dd *= -1;
} // Don't do anything for N or E
return dd;
}
\d+(\,\d+) 和 \d+(.\d+) 因为可以有浮点数
我的最终功能:
convertDMSToDD: function (dms) {
let parts = dms.split(/[^\d+(\,\d+)\d+(\.\d+)?\w]+/);
let degrees = parseFloat(parts[0]);
let minutes = parseFloat(parts[1]);
let seconds = parseFloat(parts[2].replace(',','.'));
let direction = parts[3];
console.log('degrees: '+degrees)
console.log('minutes: '+minutes)
console.log('seconds: '+seconds)
console.log('direction: '+direction)
let dd = degrees + minutes / 60 + seconds / (60 * 60);
if (direction == 'S' || direction == 'W') {
dd = dd * -1;
} // Don't do anything for N or E
return dd;
}
var url = "http://maps.google.com/maps?f=q&source=s_q&q=&vps=3&jsv=166d&sll=" + lat.parseDeg() + "," + longt.parseDeg()
function convertLatLong(input) {
if(!( input.toUpperCase() != input.toLowerCase()) ) { // if geodirection abbr. isn't exist, it should be already decimal notation
return `${input}:the coordinate already seems as decimal`
}
const parts = input.split(/[°'"]+/).join(' ').split(/[^\w\S]+/); // thanks to Shannon Antonio Black for regEx patterns
const geoLetters = parts.filter(el=> !(+el) )
const coordNumber = parts.filter(n=>(+n)).map(nr=>+nr)
const latNumber = coordNumber.slice(0,(coordNumber.length/2))
const longNumber = coordNumber.slice((coordNumber.length/2))
const reducer = function(acc,coord,curInd){
return acc + (coord/Math.pow( 60, curInd++ ))
}
let latDec = latNumber.reduce(reducer)
let longDec = longNumber.reduce(reducer)
if(geoLetters[0].toUpperCase()==='S') latDec = -latDec // if the geodirection is S or W, decimal notation should start with minus
if(geoLetters[1].toUpperCase()==='W') longDec= -longDec
const dec= [{
ltCoord: latDec,
geoLet:geoLetters[0]
},
{
longCoord: longDec,
geoLet: geoLetters[1]
}]
return dec
}
我认为这是 EC6 的更简化版本
function convertRawCoordinatesIntoDecimal(input) {
let grade = parseInt(input.substring(0, input.indexOf("°")));
let rest = input.substring(input.indexOf("°") + 1);
let minutes = parseInt(rest.substring(0, rest.indexOf("'")));
let seconds = parseInt(rest.substring(rest.indexOf("'") + 1).split('"')[0]);
return grade + (minutes + seconds / 60) / 60;
}
function getCoordinates(input) {
let parts = input.split(" "); //element 0 is N and element 2 is W coordinates
return {
[parts[1]]: convertRawCoordinatesIntoDecimal(parts[0]),
[parts[3]]: convertRawCoordinatesIntoDecimal(parts[2])
};
}
let input = `36°57'9" N 110°4'21" W`; //a test input
console.log(getCoordinates(input));
结果:
{
"N": 36.9525,
"W": 110.0725
}
说明:
" "
进行分割,得到一个由四个元素组成的字符串数组
grade
、
minutes
和
seconds
,都是数值
grade + (minutes + seconds / 60) / 60
const lonLatRegexp = (() => {
const number = `[-\u2212]?\\s*\\d+([.,]\\d+)?`;
const getCoordinate = (n: number) => (
`(` +
`(?<degrees${n}>${number})` +
`(\\s*[°]\\s*|\\s*deg\\s*|\\s+|$|(?!\\d))` +
`)(` +
`(?<minutes${n}>${number})` +
`(\\s*['\u2032]\\s*)` +
`)?(` +
`(?<seconds${n}>${number})` +
`(\\s*["\u2033]\\s*)` +
`)?(` +
`(?<hemisphere${n}>[NWSE])` +
`)?`
);
const coords = (
`(geo\\s*:\\s*)?` +
`\\s*` +
getCoordinate(1) +
`(\\s*[,;]\\s*|\\s+)` +
getCoordinate(2) +
`(\\?z=(?<zoom>\\d+))?`
);
return new RegExp(`^\\s*${coords}\\s*$`, "i");
})();
export function matchLonLat(query: string): (Point & { zoom?: number }) | undefined {
const m = lonLatRegexp.exec(query);
const prepareNumber = (str: string) => Number(str.replace(",", ".").replace("\u2212", "-").replace(/\s+/, ""));
const prepareCoords = (deg: string, min: string | undefined, sec: string | undefined, hem: string | undefined) => {
const degrees = prepareNumber(deg);
const result = Math.abs(degrees) + (min ? prepareNumber(min) / 60 : 0) + (sec ? prepareNumber(sec) / 3600 : 0);
return result * (degrees < 0 ? -1 : 1) * (hem && ["s", "S", "w", "W"].includes(hem) ? -1 : 1);
};
if (m) {
const number1 = prepareCoords(m.groups!.degrees1, m.groups!.minutes1, m.groups!.seconds1, m.groups!.hemisphere1);
const number2 = prepareCoords(m.groups!.degrees2, m.groups!.minutes2, m.groups!.seconds2, m.groups!.hemisphere2);
const zoom = m.groups!.zoom ? Number(m.groups!.zoom) : undefined;
const zoomObj = zoom != null && isFinite(zoom) ? { zoom } : {};
if ([undefined, "n", "N", "s", "S"].includes(m.groups!.hemisphere1) && [undefined, "w", "W", "e", "E"].includes(m.groups!.hemisphere2)) {
return { lat: number1, lon: number2, ...zoomObj };
} else if (["w", "W", "e", "E"].includes(m.groups!.hemisphere1) && [undefined, "n", "N", "s", "S"].includes(m.groups!.hemisphere2)) {
return { lat: number2, lon: number1, ...zoomObj };
}
}
}
// Tests
test("matchLonLat", () => {
// Simple coordinates
expect(matchLonLat("1.234,2.345")).toEqual({ lat: 1.234, lon: 2.345 });
expect(matchLonLat("-1.234,2.345")).toEqual({ lat: -1.234, lon: 2.345 });
expect(matchLonLat("1.234,-2.345")).toEqual({ lat: 1.234, lon: -2.345 });
// Integers
expect(matchLonLat("1,2")).toEqual({ lat: 1, lon: 2 });
expect(matchLonLat("-1,2")).toEqual({ lat: -1, lon: 2 });
expect(matchLonLat("1,-2")).toEqual({ lat: 1, lon: -2 });
// With unicode minus
expect(matchLonLat("\u22121.234,2.345")).toEqual({ lat: -1.234, lon: 2.345 });
expect(matchLonLat("1.234,\u22122.345")).toEqual({ lat: 1.234, lon: -2.345 });
// With spaces
expect(matchLonLat(" - 1.234 , - 2.345 ")).toEqual({ lat: -1.234, lon: -2.345 });
// With different separators
expect(matchLonLat("-1.234;-2.345")).toEqual({ lat: -1.234, lon: -2.345 });
expect(matchLonLat("-1.234 -2.345")).toEqual({ lat: -1.234, lon: -2.345 });
// Using decimal comma
expect(matchLonLat("-1,234,-2,345")).toEqual({ lat: -1.234, lon: -2.345 });
expect(matchLonLat("-1,234;-2,345")).toEqual({ lat: -1.234, lon: -2.345 });
expect(matchLonLat("-1,234 -2,345")).toEqual({ lat: -1.234, lon: -2.345 });
// Geo URI
expect(matchLonLat("geo:-1.234,-2.345")).toEqual({ lat: -1.234, lon: -2.345 });
expect(matchLonLat("geo:-1.234,-2.345?z=10")).toEqual({ lat: -1.234, lon: -2.345, zoom: 10 });
// With degree sign
expect(matchLonLat("-1.234° -2.345°")).toEqual({ lat: -1.234, lon: -2.345 });
expect(matchLonLat("-1.234 ° -2.345 °")).toEqual({ lat: -1.234, lon: -2.345 });
expect(matchLonLat("-1.234 °, -2.345 °")).toEqual({ lat: -1.234, lon: -2.345 });
// With "deg"
expect(matchLonLat("-1.234deg -2.345deg")).toEqual({ lat: -1.234, lon: -2.345 });
expect(matchLonLat("-1.234 deg -2.345 deg")).toEqual({ lat: -1.234, lon: -2.345 });
expect(matchLonLat("-1.234 deg, -2.345 deg")).toEqual({ lat: -1.234, lon: -2.345 });
// With minutes
expect(matchLonLat("-1° 24' -2° 36'")).toEqual({ lat: -1.4, lon: -2.6 });
expect(matchLonLat("-1° 24', -2° 36'")).toEqual({ lat: -1.4, lon: -2.6 });
expect(matchLonLat("-1 ° 24 ' -2 ° 36 '")).toEqual({ lat: -1.4, lon: -2.6 });
// With unicode minute sign
expect(matchLonLat("-1deg 24\u2032 -2deg 36\u2032")).toEqual({ lat: -1.4, lon: -2.6 });
expect(matchLonLat("-1deg 24\u2032, -2deg 36\u2032")).toEqual({ lat: -1.4, lon: -2.6 });
expect(matchLonLat("-1 deg 24 \u2032 -2 deg 36 \u2032")).toEqual({ lat: -1.4, lon: -2.6 });
// With seconds
expect(matchLonLat("-1° 24' 36\" -2° 36' 72\"")).toEqual({ lat: -1.41, lon: -2.62 });
expect(matchLonLat("-1° 24' 36\", -2° 36' 72\"")).toEqual({ lat: -1.41, lon: -2.62 });
expect(matchLonLat("-1 ° 24 ' 36 \" -2 ° 36 ' 72 \"")).toEqual({ lat: -1.41, lon: -2.62 });
expect(matchLonLat("-1° 36\" -2° 72\"")).toEqual({ lat: -1.01, lon: -2.02 });
// With unicode second sign
expect(matchLonLat("-1deg 24\u2032 36\u2033 -2deg 36\u2032 72\u2033")).toEqual({ lat: -1.41, lon: -2.62 });
expect(matchLonLat("-1deg 24\u2032 36\u2033, -2deg 36\u2032 72\u2033")).toEqual({ lat: -1.41, lon: -2.62 });
expect(matchLonLat("-1 deg 24 \u2032 36 \u2033 -2 deg 36 \u2032 72 \u2033")).toEqual({ lat: -1.41, lon: -2.62 });
expect(matchLonLat("-1deg 36\u2033 -2deg 72\u2033")).toEqual({ lat: -1.01, lon: -2.02 });
// Other hemisphere
expect(matchLonLat("1° 24' N 2° 36' E")).toEqual({ lat: 1.4, lon: 2.6 });
expect(matchLonLat("1° 24' S 2° 36' E")).toEqual({ lat: -1.4, lon: 2.6 });
expect(matchLonLat("1° 24' N 2° 36' W")).toEqual({ lat: 1.4, lon: -2.6 });
expect(matchLonLat("1° 24' s 2° 36' w")).toEqual({ lat: -1.4, lon: -2.6 });
// Switch lon/lat
expect(matchLonLat("1° 24' E 2° 36'")).toEqual({ lat: 2.6, lon: 1.4 });
expect(matchLonLat("1° 24' E 2° 36' N")).toEqual({ lat: 2.6, lon: 1.4 });
expect(matchLonLat("1° 24' E 2° 36' S")).toEqual({ lat: -2.6, lon: 1.4 });
expect(matchLonLat("1° 24' W 2° 36'")).toEqual({ lat: 2.6, lon: -1.4 });
expect(matchLonLat("1° 24' W 2° 36' N")).toEqual({ lat: 2.6, lon: -1.4 });
expect(matchLonLat("1° 24' W 2° 36' S")).toEqual({ lat: -2.6, lon: -1.4 });
// Invalid lon/lat combination
expect(matchLonLat("1° 24' N 2° 36' N")).toEqual(undefined);
expect(matchLonLat("1° 24' E 2° 36' E")).toEqual(undefined);
expect(matchLonLat("1° 24' S 2° 36' S")).toEqual(undefined);
expect(matchLonLat("1° 24' W 2° 36' W")).toEqual(undefined);
expect(matchLonLat("1° 24' N 2° 36' S")).toEqual(undefined);
expect(matchLonLat("1° 24' S 2° 36' N")).toEqual(undefined);
expect(matchLonLat("1° 24' W 2° 36' E")).toEqual(undefined);
expect(matchLonLat("1° 24' E 2° 36' W")).toEqual(undefined);
});
我的代码支持以下格式(及其组合以及带有附加空格的变体):
-1.234,-2.345
geo:-1.234,-2.345
geo:-1.234,-2.345?z=10
-1.234;-2.345
(分号分隔符)
-1.234 -2.345
(空格分隔符)
-1,234 -2,345
(小数点逗号)
−1.234,−2.345
(Unicode 减去)
-1.234°, -2.345°
1° 23', 2° 34'
1° 23' 45.67", 2° 34' 56.78"
1 deg 23' 45.67", 2 deg 34' 56.78"
1° 45.67", 2° 56.78"
(秒但没有分钟)
1° 23′ 45.67″, 2° 34′ 56.78″
(Unicode 分钟和秒)
-1° 23' 45.67", -2° 34' 56.78"
1° 23' 45.67" S, 2° 34' 56.78" W
2° 34' 56.78" W 1° 23' 45.67" S
(纬度/经度切换)