将纬度和经度转换为十进制值

问题描述 投票:0回答:10

我的 GPS 信息以以下形式呈现:

北纬 36°57'9" 西经 110°4'21"

我可以使用 Chris Veness 的 javascript 函数将度、分和秒转换为数字度数,但首先需要将 GPS 信息解析为单独的纬度和经度字符串(带有 NSEW 后缀)。我已阅读 stackoverflow 上的相关帖子,但我不是正则表达式专家(也不是程序员),需要一些解析功能的帮助。将此字符串解析为纬度和经度以便在转换函数中使用的最佳方法是什么?

所有这一切的结果将是一个 Web 链接,单击该链接即可查看位置的 Google 地图表示。

javascript regex geolocation gps geocoding
10个回答
75
投票
要解析您的输入,请使用以下命令。

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获取点


20
投票
更正了上述函数并将输出设为对象。

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; }
    

11
投票
我的调整版本将字符串部分强制转换为数字,以便它们实际上可以添加在一起而不是连接。它还处理秒组件常见的十进制值:

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; }
    

8
投票
这是我对此的看法:

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

这就是我所需要的。


4
投票
我在这个函数上得到了一些 NaN 并且需要这样做(不要问我为什么)

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; }
    

4
投票
我使用

\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; }
    

3
投票
Joe,你提到的脚本已经做了你想要的事情。有了它,您可以转换纬度和经度,并将其放入链接中以在 Google 地图中查看位置:

var url = "http://maps.google.com/maps?f=q&source=s_q&q=&vps=3&jsv=166d&sll=" + lat.parseDeg() + "," + longt.parseDeg()
    

0
投票
使用 Shannon Antonio Black 的正则表达式模式(上面),我的解决方案是:

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 的更简化版本


0
投票

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 }
说明:

    我们按
  • " "
     进行分割,得到一个由四个元素组成的字符串数组
  • 元素 1 将是第一个坐标的名称,元素 3 将是第二个坐标的名称
  • 元素 0 将是第一个坐标的值,元素 2 将是第二个坐标的值
  • 我们将元素分别分解为
  • grade
    minutes
    seconds
    ,都是数值
  • 公式为
  • grade + (minutes + seconds / 60) / 60
    
    

0
投票
抱歉还有另一个算法,但我需要在用户提供的输入上运行它,所以我需要检查它是否完全匹配所需的格式。为了实现这一点,我在整个字符串上使用正则表达式。

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
    (纬度/经度切换)
如果输入的格式无效,则返回 undefined。

© www.soinside.com 2019 - 2024. All rights reserved.