如何将度分秒转换为度十进制

19

我从GPS接收到的纬度和经度格式如下:

纬度:78°55'44.29458"N

我需要将这些数据转换为:

纬度:78.9288888889

我在这里找到了这段代码:链接

import re

def dms2dd(degrees, minutes, seconds, direction):
    dd = float(degrees) + float(minutes)/60 + float(seconds)/(60*60);
    if direction == 'E' or direction == 'S':
        dd *= -1
    return dd;

def dd2dms(deg):
    d = int(deg)
    md = abs(deg - d) * 60
    m = int(md)
    sd = (md - m) * 60
    return [d, m, sd]

def parse_dms(dms):
    parts = re.split('[^\d\w]+', dms)
    lat = dms2dd(parts[0], parts[1], parts[2], parts[3])
 
    return (lat)

dd = parse_dms("78°55'44.33324"N )

print(dd)

它适用于这种格式

dd = parse_dms("78°55'44.33324'N" )

但它对我的数据格式不起作用。有谁能帮我解决这个问题吗?

10个回答

25

这是我的一句话总结(好吧,好吧——也许是两句话):)

import re
lat = '''51°36'9.18"N'''
deg, minutes, seconds, direction =  re.split('[°\'"]', lat)
(float(deg) + float(minutes)/60 + float(seconds)/(60*60)) * (-1 if direction in ['W', 'S'] else 1)

这将输出 51.60255


16

上述函数 dms2dd 是不正确的。

实际情况(带有错误):

if direction == 'E' or direction == 'N':
        dd *= -1

更正后的条件:

if direction == '**W**' or direction == '**S**':
        dd *= -1

10
问题在于秒数 44.29458 被分割成了 .
你可以直接定义分割字符(而不是定义不能分割的位置):
>>> re.split('[°\'"]+', """78°55'44.29458"N""")
['78', '55', '44.29458', 'N']

或者保留正则表达式的原始形式并合并第2部分和第3部分。
dms2dd(parts[0], parts[1], parts[2] + "." + parts[3], parts[4])

更新:

您的方法调用dd = parse_dms("78°55'44.33324"N )是语法错误。请添加闭合的"并转义其他的一个。或者使用三个引号进行字符串定义:

parse_dms("""78°55'44.29458"N""")

当我将第二个选项添加到代码中时,它仍然无法正常工作。 - bikuser
如果你像这样调用函数 parse_dms("78°55'44.33324"N ),那就是语法错误。你需要像我这样传递字符串:parse_dms("""78°55'44.29458"N""")。或者你可以转义引号,如 "78°55'44.29458\"N"'78°55\'44.29458"N'。更多细节,你应该查看 Python 中定义字符串的语法。 - Falko
啊,好的,现在我明白了。谢谢Falko :) - bikuser
如果我有一个包含大量这样坐标的数组,那么我如何使用这个函数进行转换? - bikuser

4

您可以使用此模块:https://pypi.org/project/dms2dec/

将度分秒转换为十进制。

用法

from dms2dec.dms_convert import dms2dec

dms2dec('''36°44'47.69"N''') # converts to dec
dms2dec('''3° 2'33.53"E''') # converts to dec

4

我知道这是一个老问题,但是对于那些一直在关注的人,我想指出你在 dms2dd() 函数中有错误的逻辑关系,涉及到小数的符号。您当前有:

if direction == 'E' or direction == 'N':
    dd *= -1

但只有在方向为本初子午线以西(W)或赤道以南(S)时,才应该为负。因此应该改为:

if direction == 'W' or direction == 'S':
    dd *= -1

这是一份详细指南中的引用:https://www.ubergizmo.com/how-to/read-gps-coordinates/ 纬度线的坐标表示赤道以北,因为它是正数。如果数字为负,则表示赤道以南。 经度线的坐标表示本初子午线以东,因为它是正数。如果数字为负,则表示本初子午线以西。

2

我稍微修改了re:

parts = re.split('[^\d\w\.]+', dms)

正如@Falko建议的那样,您可以使用双引号或转义引号字符来使其正常工作。

parse_dms("53°19\'51.8\"N")

0

如果你的数据在一个DataFrame中,你可以使用库DataPrep中的函数clean_lat_long()。使用pip install dataprep来安装DataPrep。

from dataprep.clean import clean_lat_long
df = pd.DataFrame({"Latitude": ["78°55'44.29458''N", "51°36'9.18''N"]})

df2 = clean_lat_long(df, lat_col="Latitude")
            Latitude  Latitude_clean
0  78°55'44.29458''N         78.9290
1      51°36'9.18''N         51.6026

这看起来不错,但不幸的是,在使用Anaconda安装时,它想要大规模降级pandas库,似乎与pandas 2不兼容。 - Richard Whitehead

0
你可以简单地使用pygeodesy,这个库对于许多其他功能非常有用,比如找到坐标中点、精确的距离和方位角计算等。
from pygeodesy import parse3llh, fstr

x = parse3llh('000° 00′ 05.31″W, 51° 28′ 40.12″ N')
print (fstr(x, prec=6))

结果

51.477811, -0.001475, 0.0

0

对于多个坐标,您可以使用pandas读取它们。格式很重要-不应有任何空格。可以使用replace函数删除空格。输出可以轻松保存为文本文件或电子表格。我只是打印了它们进行验证,并将小数位置四舍五入。

### read input file
df = pd.read_excel('dms.xlsx')

n = len(df)

for i in range(n):
  Lat_d = round(parse_dms(df.Lat[i].replace(" ", "")),4)
  Long_d = round(parse_dms(df.Long[i].replace(" ", "")),4)
  print(Lat_d, Long_d)

parse_dms 是 JavaScript。 - Richard Whitehead

0

https://github.com/medo-mi/dms-to-dd

import re

#Degrees Minutes Seconds to Decimal Degrees
def dms_dd(dd):
    dd = f"""{dd}"""
    dd = re.sub('[^a-zA-Z0-9. ]', '', dd)
    dd = dd.split(" ")
    return round(float(dd[0])+(float(dd[1])/60)+(float(dd[2])/3600), 8)

似乎忽略了北、南、东、西的信息。 - Richard Whitehead

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接