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

发布于 2024-07-27 16:01:42 字数 389 浏览 5 评论 0原文

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

36°57'9" N 110°4'21" W

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

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

I have GPS information presented in the form:

36°57'9" N 110°4'21" W

I can use the javascript functions of Chris Veness to convert degrees, minutes and seconds to numeric degrees, but first need to parse the GPS info into the individual latitude and longitude strings (with NSEW suffixes). I have read related posts on stackoverflow, but am not a regex expert (nor a programmer) and need some help with the parsing function. What's the best way to parse this string into latitude and longitude for use in the conversion function?

The result of all this will be a Web link that one can click on to see a Google map representation of location.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

若相惜即相离 2024-08-03 16:01:43

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

const lonLatRegexp = (() => {
    const number = `[-\u2212]?\\s*\\d+([.,]\\d+)?`;

    const getCoordinate = (n: number) => (
        `(` +
            `(?<hemispherePrefix${n}>[NWSE])` +
        `)?(` +
            `(?<degrees${n}>${number})` +
            `(\\s*[°]\\s*|\\s*deg\\s*|\\s+|$|(?!\\d))` +
        `)(` +
            `(?<minutes${n}>${number})` +
            `(\\s*['\u2032\u2019]\\s*)` +
        `)?(` +
            `(?<seconds${n}>${number})` +
            `(\\s*["\u2033\u201d]\\s*)` +
        `)?(` +
            `(?<hemisphereSuffix${n}>[NWSE])` +
        `)?`
    );

    const coords = (
        `(geo\\s*:\\s*)?` +
        `\\s*` +
        getCoordinate(1) +
        `(?<separator>\\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 { hemispherePrefix1, degrees1, minutes1, seconds1, hemisphereSuffix1, separator, hemispherePrefix2, degrees2, minutes2, seconds2, hemisphereSuffix2, zoom } = m.groups!; let hemisphere1: string | undefined = undefined, hemisphere2: string | undefined = undefined; if (hemispherePrefix1 && !hemisphereSuffix1 && hemispherePrefix2 && !hemisphereSuffix2) { [hemisphere1, hemisphere2] = [hemispherePrefix1, hemispherePrefix2]; } else if (!hemispherePrefix1 && hemisphereSuffix1 && !hemispherePrefix2 && hemisphereSuffix2) { [hemisphere1, hemisphere2] = [hemisphereSuffix1, hemisphereSuffix2]; } else if (hemispherePrefix1 && hemisphereSuffix1 && !hemispherePrefix2 && !hemisphereSuffix2 && !separator.trim()) { // Coordinate 2 has a hemisphere prefix, but because the two coordinates are separated by whitespace only, it was matched as a coordinate 1 suffix [hemisphere1, hemisphere2] = [hemispherePrefix1, hemisphereSuffix1]; } else if (hemispherePrefix1 || hemisphereSuffix1 || hemispherePrefix2 || hemisphereSuffix2) { // Unsupported combination of hemisphere prefixes/suffixes return undefined; } // else: no hemispheres specified const coordinate1 = prepareCoords(degrees1, minutes1, seconds1, hemisphere1); const coordinate2 = prepareCoords(degrees2, minutes2, seconds2, hemisphere2); const zoomNumber = zoom ? Number(zoom) : undefined; const zoomObj = zoomNumber != null && isFinite(zoomNumber) ? { zoom: zoomNumber } : {}; // Handle cases where lat/lon are switched if ([undefined, "n", "N", "s", "S"].includes(hemisphere1) && [undefined, "w", "W", "e", "E"].includes(hemisphere2)) { return { lat: coordinate1, lon: coordinate2, ...zoomObj }; } else if ((["w", "W", "e", "E"] as Array<string | undefined>).includes(hemisphere1) && [undefined, "n", "N", "s", "S"].includes(hemisphere2)) { return { lat: coordinate2, lon: coordinate1, ...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("−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 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′ -2deg 36′")).toEqual({ lat: -1.4, lon: -2.6 }); expect(matchLonLat("-1deg 24′, -2deg 36′")).toEqual({ lat: -1.4, lon: -2.6 }); expect(matchLonLat("-1 deg 24 ′ -2 deg 36 ′")).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′ 36″ -2deg 36′ 72″")).toEqual({ lat: -1.41, lon: -2.62 }); expect(matchLonLat("-1deg 24′ 36″, -2deg 36′ 72″")).toEqual({ lat: -1.41, lon: -2.62 }); expect(matchLonLat("-1 deg 24 ′ 36 ″ -2 deg 36 ′ 72 ″")).toEqual({ lat: -1.41, lon: -2.62 }); expect(matchLonLat("-1deg 36″ -2deg 72″")).toEqual({ lat: -1.01, lon: -2.02 }); // With unicode quote signs expect(matchLonLat("-1deg 24’ 36” -2deg 36’ 72”")).toEqual({ lat: -1.41, lon: -2.62 }); expect(matchLonLat("-1deg 24’ 36”, -2deg 36’ 72”")).toEqual({ lat: -1.41, lon: -2.62 }); expect(matchLonLat("-1 deg 24 ’ 36 ” -2 deg 36 ’ 72 ”")).toEqual({ lat: -1.41, lon: -2.62 }); expect(matchLonLat("-1deg 36” -2deg 72”")).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("N 1° 24' E 2° 36'")).toEqual({ lat: 1.4, lon: 2.6 }); expect(matchLonLat("1° 24' S 2° 36' E")).toEqual({ lat: -1.4, lon: 2.6 }); expect(matchLonLat("S 1° 24' E 2° 36'")).toEqual({ lat: -1.4, lon: 2.6 }); expect(matchLonLat("1° 24' N 2° 36' W")).toEqual({ lat: 1.4, lon: -2.6 }); expect(matchLonLat("N 1° 24' W 2° 36'")).toEqual({ lat: 1.4, lon: -2.6 }); expect(matchLonLat("1° 24' s 2° 36' w")).toEqual({ lat: -1.4, lon: -2.6 }); expect(matchLonLat("s 1° 24' w 2° 36'")).toEqual({ lat: -1.4, lon: -2.6 }); // Switch lon/lat expect(matchLonLat("1° 24' E 2° 36' N")).toEqual({ lat: 2.6, lon: 1.4 }); expect(matchLonLat("E 1° 24' N 2° 36'")).toEqual({ lat: 2.6, lon: 1.4 }); expect(matchLonLat("1° 24' E 2° 36' S")).toEqual({ lat: -2.6, lon: 1.4 }); expect(matchLonLat("E 1° 24' S 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("W 1° 24' N 2° 36'")).toEqual({ lat: 2.6, lon: -1.4 }); expect(matchLonLat("1° 24' W 2° 36' S")).toEqual({ lat: -2.6, lon: -1.4 }); expect(matchLonLat("W 1° 24' S 2° 36'")).toEqual({ lat: -2.6, lon: -1.4 }); // Practical examples expect(matchLonLat("N 53°53’42.8928” E 10°44’13.4844”")).toEqual({ lat: 53.895248, lon: 10.737079 }); // Park4night expect(matchLonLat("53°53'42.8928\"N 10°44'13.4844\"E")).toEqual({ lat: 53.895248, lon: 10.737079 }); // Google Maps // 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); // Invalid hemisphere prefix/suffix combination expect(matchLonLat("N 1° 24' 2° 36'")).toEqual(undefined); expect(matchLonLat("1° 24' E 2° 36'")).toEqual(undefined); expect(matchLonLat("1° 24' 2° 36' E")).toEqual(undefined); expect(matchLonLat("N 1° 24' E 2° 36' E")).toEqual(undefined); expect(matchLonLat("N 1° 24' 2° 36' E")).toEqual(undefined); expect(matchLonLat("1° 24' E N 2° 36'")).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 度 23
  • ' 45.67", 2 度 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” (Unicode 引号表示分钟和秒)
  • -1° 23' 45.67", -2° 34' 56.78"
  • 1° 23' 45.67 " S, 2° 34' 56.78" W(半球后缀)
  • S 1° 23' 45.67", W 2° 34' 56.78"(半球前缀)
  • 2° 34 ' 56.78" W 1° 23' 45.67" S(纬度/经度已切换)

如果输入的格式无效,则返回 undefined。

Sorry for yet another algorithm, but I needed to run this on user-provided input, so I need to check whether it matches the desired format at all. To achieve this, I’m using a regexp on the whole string.

const lonLatRegexp = (() => {
    const number = `[-\u2212]?\\s*\\d+([.,]\\d+)?`;

    const getCoordinate = (n: number) => (
        `(` +
            `(?<hemispherePrefix${n}>[NWSE])` +
        `)?(` +
            `(?<degrees${n}>${number})` +
            `(\\s*[°]\\s*|\\s*deg\\s*|\\s+|$|(?!\\d))` +
        `)(` +
            `(?<minutes${n}>${number})` +
            `(\\s*['\u2032\u2019]\\s*)` +
        `)?(` +
            `(?<seconds${n}>${number})` +
            `(\\s*["\u2033\u201d]\\s*)` +
        `)?(` +
            `(?<hemisphereSuffix${n}>[NWSE])` +
        `)?`
    );

    const coords = (
        `(geo\\s*:\\s*)?` +
        `\\s*` +
        getCoordinate(1) +
        `(?<separator>\\s*[,;]\\s*|\\s+)` +
        getCoordinate(2) +
        `(\\?z=(?<zoom>\\d+))?`
    );

    return new RegExp(`^\\s*${coords}\\s*

Sorry for yet another algorithm, but I needed to run this on user-provided input, so I need to check whether it matches the desired format at all. To achieve this, I’m using a regexp on the whole string.

, "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 { hemispherePrefix1, degrees1, minutes1, seconds1, hemisphereSuffix1, separator, hemispherePrefix2, degrees2, minutes2, seconds2, hemisphereSuffix2, zoom } = m.groups!; let hemisphere1: string | undefined = undefined, hemisphere2: string | undefined = undefined; if (hemispherePrefix1 && !hemisphereSuffix1 && hemispherePrefix2 && !hemisphereSuffix2) { [hemisphere1, hemisphere2] = [hemispherePrefix1, hemispherePrefix2]; } else if (!hemispherePrefix1 && hemisphereSuffix1 && !hemispherePrefix2 && hemisphereSuffix2) { [hemisphere1, hemisphere2] = [hemisphereSuffix1, hemisphereSuffix2]; } else if (hemispherePrefix1 && hemisphereSuffix1 && !hemispherePrefix2 && !hemisphereSuffix2 && !separator.trim()) { // Coordinate 2 has a hemisphere prefix, but because the two coordinates are separated by whitespace only, it was matched as a coordinate 1 suffix [hemisphere1, hemisphere2] = [hemispherePrefix1, hemisphereSuffix1]; } else if (hemispherePrefix1 || hemisphereSuffix1 || hemispherePrefix2 || hemisphereSuffix2) { // Unsupported combination of hemisphere prefixes/suffixes return undefined; } // else: no hemispheres specified const coordinate1 = prepareCoords(degrees1, minutes1, seconds1, hemisphere1); const coordinate2 = prepareCoords(degrees2, minutes2, seconds2, hemisphere2); const zoomNumber = zoom ? Number(zoom) : undefined; const zoomObj = zoomNumber != null && isFinite(zoomNumber) ? { zoom: zoomNumber } : {}; // Handle cases where lat/lon are switched if ([undefined, "n", "N", "s", "S"].includes(hemisphere1) && [undefined, "w", "W", "e", "E"].includes(hemisphere2)) { return { lat: coordinate1, lon: coordinate2, ...zoomObj }; } else if ((["w", "W", "e", "E"] as Array<string | undefined>).includes(hemisphere1) && [undefined, "n", "N", "s", "S"].includes(hemisphere2)) { return { lat: coordinate2, lon: coordinate1, ...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("−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 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′ -2deg 36′")).toEqual({ lat: -1.4, lon: -2.6 }); expect(matchLonLat("-1deg 24′, -2deg 36′")).toEqual({ lat: -1.4, lon: -2.6 }); expect(matchLonLat("-1 deg 24 ′ -2 deg 36 ′")).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′ 36″ -2deg 36′ 72″")).toEqual({ lat: -1.41, lon: -2.62 }); expect(matchLonLat("-1deg 24′ 36″, -2deg 36′ 72″")).toEqual({ lat: -1.41, lon: -2.62 }); expect(matchLonLat("-1 deg 24 ′ 36 ″ -2 deg 36 ′ 72 ″")).toEqual({ lat: -1.41, lon: -2.62 }); expect(matchLonLat("-1deg 36″ -2deg 72″")).toEqual({ lat: -1.01, lon: -2.02 }); // With unicode quote signs expect(matchLonLat("-1deg 24’ 36” -2deg 36’ 72”")).toEqual({ lat: -1.41, lon: -2.62 }); expect(matchLonLat("-1deg 24’ 36”, -2deg 36’ 72”")).toEqual({ lat: -1.41, lon: -2.62 }); expect(matchLonLat("-1 deg 24 ’ 36 ” -2 deg 36 ’ 72 ”")).toEqual({ lat: -1.41, lon: -2.62 }); expect(matchLonLat("-1deg 36” -2deg 72”")).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("N 1° 24' E 2° 36'")).toEqual({ lat: 1.4, lon: 2.6 }); expect(matchLonLat("1° 24' S 2° 36' E")).toEqual({ lat: -1.4, lon: 2.6 }); expect(matchLonLat("S 1° 24' E 2° 36'")).toEqual({ lat: -1.4, lon: 2.6 }); expect(matchLonLat("1° 24' N 2° 36' W")).toEqual({ lat: 1.4, lon: -2.6 }); expect(matchLonLat("N 1° 24' W 2° 36'")).toEqual({ lat: 1.4, lon: -2.6 }); expect(matchLonLat("1° 24' s 2° 36' w")).toEqual({ lat: -1.4, lon: -2.6 }); expect(matchLonLat("s 1° 24' w 2° 36'")).toEqual({ lat: -1.4, lon: -2.6 }); // Switch lon/lat expect(matchLonLat("1° 24' E 2° 36' N")).toEqual({ lat: 2.6, lon: 1.4 }); expect(matchLonLat("E 1° 24' N 2° 36'")).toEqual({ lat: 2.6, lon: 1.4 }); expect(matchLonLat("1° 24' E 2° 36' S")).toEqual({ lat: -2.6, lon: 1.4 }); expect(matchLonLat("E 1° 24' S 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("W 1° 24' N 2° 36'")).toEqual({ lat: 2.6, lon: -1.4 }); expect(matchLonLat("1° 24' W 2° 36' S")).toEqual({ lat: -2.6, lon: -1.4 }); expect(matchLonLat("W 1° 24' S 2° 36'")).toEqual({ lat: -2.6, lon: -1.4 }); // Practical examples expect(matchLonLat("N 53°53’42.8928” E 10°44’13.4844”")).toEqual({ lat: 53.895248, lon: 10.737079 }); // Park4night expect(matchLonLat("53°53'42.8928\"N 10°44'13.4844\"E")).toEqual({ lat: 53.895248, lon: 10.737079 }); // Google Maps // 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); // Invalid hemisphere prefix/suffix combination expect(matchLonLat("N 1° 24' 2° 36'")).toEqual(undefined); expect(matchLonLat("1° 24' E 2° 36'")).toEqual(undefined); expect(matchLonLat("1° 24' 2° 36' E")).toEqual(undefined); expect(matchLonLat("N 1° 24' E 2° 36' E")).toEqual(undefined); expect(matchLonLat("N 1° 24' 2° 36' E")).toEqual(undefined); expect(matchLonLat("1° 24' E N 2° 36'")).toEqual(undefined); });

My code supports the following formats (and combinations thereof and variants with additional white spaces):

  • -1.234,-2.345
  • geo:-1.234,-2.345
  • geo:-1.234,-2.345?z=10
  • -1.234;-2.345 (semicolon separator)
  • -1.234 -2.345 (space separator)
  • -1,234 -2,345 (decimal comma)
  • −1.234,−2.345 (Unicode minus)
  • -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" (seconds but no minutes)
  • 1° 23′ 45.67″, 2° 34′ 56.78″ (Unicode minutes and seconds)
  • 1° 23’ 45.67”, 2° 34’ 56.78” (Unicode quotes for minutes and seconds)
  • -1° 23' 45.67", -2° 34' 56.78"
  • 1° 23' 45.67" S, 2° 34' 56.78" W (hemisphere suffix)
  • S 1° 23' 45.67", W 2° 34' 56.78" (hemisphere prefix)
  • 2° 34' 56.78" W 1° 23' 45.67" S (latitude/longitude switched)

If the input has an invalid format, undefined is returned.

云雾 2024-08-03 16:01:43

使用 parse-dms 库:

var parseDMS = require(`parse-dms`);
parseDMS(`36°57'9" N 110°4'21" W`); // { lat: 36.9525, lon: -110.07249999999999 }

Using the parse-dms library:

var parseDMS = require(`parse-dms`);
parseDMS(`36°57'9" N 110°4'21" W`); // { lat: 36.9525, lon: -110.07249999999999 }
段念尘 2024-08-03 16:01:42

要解析您的输入,请使用以下命令。

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 地图 API)

To parse your input use the following.

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

The following will convert your DMS to 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;
}

So your input would produce the following:

36°57'9" N  = 36.9525000
110°4'21" W = -110.0725000

Decimal coordinates can be fed into google maps to get points via GLatLng(lat, lng) (Google Maps API)

2024-08-03 16:01:42

更正了上述函数并使输出成为对象。

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

Corrected the above functions and made the output an object.

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;
}
梅倚清风 2024-08-03 16:01:42

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

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

My tweaked version coerces the string parts into Numbers so that they can actually be added together rather than concatenated. It also handles decimal values which are common for the Seconds component:

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

The following will convert your DMS to 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;
}
爱人如己 2024-08-03 16:01:42

这是我对此的看法:

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

这就是我需要的。

here is my take on this:

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;

}

This function doesn't handle all types of lat / long types, but it handles the following formats:

-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

Which is what i needed.

挖鼻大婶 2024-08-03 16:01:42

我使用 \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;
   }

I used \d+(\,\d+) and \d+(.\d+) because can have float numbers

My final function:

 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;
   }
酷炫老祖宗 2024-08-03 16:01:42

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

function ConvertDMSToDD(degrees, minutes, seconds, direction) {
    var dd = degrees + (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;
}

I got some NaN's on this function and needed to do this (don't ask me why)

function ConvertDMSToDD(degrees, minutes, seconds, direction) {
    var dd = degrees + (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;
}
百善笑为先 2024-08-03 16:01:42

乔,你提到的脚本已经达到了你想要的效果。 有了它,您可以转换纬度和经度,并将其放入链接中以在 Google 地图中查看位置:

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

Joe, the script you've mentioned already did what do you want. With it you can convert lat and long and put it into link to see location in Google map:

var url = "http://maps.google.com/maps?f=q&source=s_q&q=&vps=3&jsv=166d&sll=" + lat.parseDeg() + "," + longt.parseDeg()
为你拒绝所有暧昧 2024-08-03 16:01:42

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

Using Shannon Antonio Black's regex pattern (above), my solution is:

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
}

I think that is more simplified version with EC6

聚集的泪 2024-08-03 16:01:42
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分钟seconds,所有数值的
  • 公式为等级+(分+秒/60)/60

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

Result:

{
  "N": 36.9525,
  "W": 110.0725
}

Explanation:

  • we split by " ", getting an array of strings of four elements
  • element 1 will be the name of the first coordinate and element 3 will be the name of the second coordinate
  • element 0 will be the value of the first coordinate and element 2 will be the value of the second coordinate
  • we dissect the elements into grade, minutes and seconds respectively, all numerical values
  • the formula is grade + (minutes + seconds / 60) / 60
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文