将 GPS 纬度/经度从不同格式转换为一种格式(在 PHP 中)

Posted

技术标签:

【中文标题】将 GPS 纬度/经度从不同格式转换为一种格式(在 PHP 中)【英文标题】:converting GPS latitude/longitude from different formats to one format (in PHP) 【发布时间】:2010-06-16 10:38:24 【问题描述】:

我正在尝试在我的应用程序中内置对位置的支持,并且我希望用户能够以各种方式输入 gps 坐标。我需要将以下所有内容转换为:纬度 - 方向(N/s)、度、分、秒;经度 (E/W) - 度、分、秒。

请注意,每个用户输入都将在一行中。我希望我的用户仅以一种方式输入,但 ppl 肯定会以下列方式之一输入...:

例如: 9.182, -39.140625 9.182 / -39.140625 9.182,-39.140625 9.182 -39.140625 21° 16' 674S[some_separator]27° 30' 318E 21 16 674S[some_separator]27 30 318E

[some_separator] 也可以是一个空格...

最终格式需要beas: 纬度.direction = 南 纬度.度 = 21 纬度.分钟 = 16 纬度.秒 = 674 longitude.direction = 东 经度.degrees = 27 经度.分钟 = 30 longitude.seconds = 318

(a) 要求普通非技术用户输入 GPS 坐标的最简单方法是什么?s (b) 我如何将上述内容转换为最终格式?任何处理这些数据输入变化的内置函数?

我见过GPS format in php - 但我需要处理更多样化的输入。

【问题讨论】:

【参考方案1】:

我一直在进一步解决这个问题(我注意到你编辑了你的问题)。

A) 要求普通非技术用户输入 GPS 坐标的最简单方法是什么?

让非技术用户输入详细信息的最简单、最用户友好的方式是使用 Google 地图。这将允许您使用谷歌地理编码器来解析他们的输入(并提供更标准化和格式化的输出)。此外,如果用户输入的位置是他们当前的位置,您可以考虑使用某些现代浏览器提供的地理定位功能。

B) 如何将上述内容转换为最终格式?是否有任何内置函数可以处理这些数据输入变化?

根据您的测试数据,我制定了一个 PHP 正则表达式来解析它并返回可预测的标准化输出。

$rexp = '/^(\-?\d+(?:\.\d+)?)(?:\D+(\d+)\D+(\d+)([NS]?))?[^\d\-]+(\-?\d+(?:\.\d+)?)(?:\D+(\d+)\D+(\d+)([EW]?))?$/i';

$data = array(
  "21° 16' 674S, 27° 30' 318E" ,
  '21 16 674S, 27 30 318E' ,
  '9.182, -39.140625' ,
  '9.182 / -39.140625' ,
  '9.182,-39.140625' ,
  '9.182 -39.140625'
);

foreach( $data as $test ) 
  if( !preg_match( $rexp , $test , $matches ) ) 
    echo '<b>Failed</b>';
   else 
    // Match Found
  

输出:

array(
  [0] => Matched Text ,
  [1] => Full Degrees ,
  [2] => Minutes ,
  [3] => Seconds ,
  [4] => Hemisphere (N or S) ,
  [5] => Full Degrees ,
  [6] => Minutes ,
  [7] => Seconds ,
  [8] => Hemisphere (E or W)
)

例子:

// Matching 21° 16' 674S, 27° 30' 318E
array(
  [0] => "21° 16' 674S, 27° 30' 318E" ,
  [1] => "21" , [2] => "16" , [3] => "674" , [4] => "S" ,
  [5] => "27" , [6] => "30" , [7] => "318" , [8] => "E"
)

// Matching 21 16 674S, 27 30 318E
array(
  [0]=> "21 16 674S, 27 30 318E" ,
  [1]=> "21" , [2]=> "16" , [3]=> "674" , [4]=> "S" ,
  [5]=> "27" , [6]=> "30" , [7]=> "318" , [8]=> "E"
)

// Matching 9.182, -39.140625
array(
  [0]=> "9.182, -39.140625" ,
  [1]=>   "9.182" ,    [2]=> "" , [3]=> "" , [4]=> "" ,
  [5]=> "-39.140625" , [6]=> "" , [7]=> "" , [8]=> ""
)

// Matching 9.182 / -39.140625
array(
  [0]=> "9.182 / -39.140625" ,
  [1]=>   "9.182" ,    [2]=> "" , [3]=> "" , [4]=> "" ,
  [5]=> "-39.140625" , [6]=> "" , [7]=> "" , [8]=> ""
)

// Matching 9.182,-39.140625
array(
  [0]=> "9.182,-39.140625" ,
  [1]=>   "9.182" ,    [2]=> "" , [3]=> "" , [4]=> "" ,
  [5]=> "-39.140625" , [6]=> "" , [7]=> "" , [8]=> ""
)

// Matching 9.182 -39.140625
array(
  [0]=> "9.182 -39.140625" ,
  [1]=>   "9.182" ,    [2]=> "" , [3]=> "" , [4]=> "" ,
  [5]=> "-39.140625" , [6]=> "" , [7]=> "" , [8]=> ""
)

随后,您可以处理正则表达式的结果,为 Lat/Long 链接生成一个浮点数:

// (Replacing the "Match Found" comment)
  $latitude  = $matches[1]+((int)$matches[2]/60)+((int)$matches[3]/3600)*(strtolower($matches[4])=='s'?-1:1);
  $longitude = $matches[5]+((int)$matches[6]/60)+((int)$matches[7]/3600)*(strtolower($matches[8])=='w'?-1:1);

产生:

// Matching 21° 16' 674S, 27° 30' 318E
$latitude  = -21.4538888889
$longitude =  27.5883333333

// Matching 21 16 674S, 27 30 318E
$latitude  = -21.4538888889
$longitude =  27.5883333333

// Matching 9.182, -39.140625
$latitude  =   9.182
$longitude = -39.140625

// Matching 9.182 / -39.140625
$latitude  =   9.182
$longitude = -39.140625

// Matching 9.182,-39.140625
$latitude  =   9.182
$longitude = -39.140625

// Matching 9.182 -39.140625
$latitude  =   9.182
$longitude = -39.140625

【讨论】:

向卢卡诺斯致敬,感谢他的精彩尝试……!我仍在测试它,但快速浏览一下就知道它完全/非常接近我需要的东西!!! 在转换为浮点数时,您仅在最后一个组件上使用 -1 乘法。您的代码给出的结果与您在答案中列出的结果不同,要修复它,您需要将翻译更改为 $latitude = ($matches[1]+((int)$matches[2]/60)+((int)$matches[3]/3600))*(strtolower($matches[4])=='s'?-1:1); $longitude = ($matches[5]+((int)$matches[6]/60)+((int)$matches[7]/3600))*(strtolower($matches[8])=='w'?-1:1);【参考方案2】:

我认为最好的方法是尽可能限制用户输入,以便他们只能输入有效数据。让用户为您分离令牌中的数据,而不是您尝试考虑每一种可能性。根据需要使用尽可能多的文本框/下拉列表/等来强制用户正确填充数据。我认为最好尽量减少您将要进行的文本解析的数量和变化。

用户获取数据的格式是什么?如果它只是一个十进制的纬度/经度,例如(50.32,123.55),那么只需简单地输入两个可以填写的数字输入,并可能在框中包含一个示例值。如果用户以度/分/秒格式获取数据,那么他们需要为每个纬度和经度填写这些字段。如果您同时允许小数和度数表示,它应该涵盖您的所有用户。

根据需要将数据分解为足够多的标记,以确保在程序中解释数据时的一致性!

编辑: 如果您认为您的网站可以接受,一个时髦的想法是有一个谷歌地图,用户可以在其中将标记拖到他们想要的位置。然后,您可以从该标记以一致的方式获取 GPS 坐标,并将其用于您需要做的任何进一步的工作!

【讨论】:

【参考方案3】:
    使用explode() 或preg_split() 分割纬度和经度。 对于纬度和经度,确定它是以浮点数还是分钟数给出。 将值转换为度数(作为浮点数)

【讨论】:

【参考方案4】:

您最好的(但不可否认,最不可靠)的方法是推动用户行为,尝试让他们以标准化且易于解析的格式格式化数据。即使只有一两种简单的主要格式来尝试并鼓励他们转换为一个很好的步骤,也可以减少所需的纠错/格式。

除此之外,我建议创建正则表达式和这些正则表达式背后的函数以标准化您将要使用的数据将是一个解决方案。

我已经针对您提供的测试数据运行了一些正则表达式,但在创建这方面的防弹解决方案时遇到了麻烦(您可能需要有几种不同的模式来选择每种组合)。

我什至尝试解析通过Google Geocoding API 提供的一些测试数据(通常,这是一个相当有弹性的系统,允许纯文本寻址,以及多种纬度/经度格式),但是,没有乐趣.

输入的数据越标准,就越容易创建准确的信息。也许将地图(谷歌地图或其他)集成到输入阶段可以让您更准确地验证输入。

【讨论】:

以上是关于将 GPS 纬度/经度从不同格式转换为一种格式(在 PHP 中)的主要内容,如果未能解决你的问题,请参考以下文章

GPS 将 16 位十六进制值转换为经度和纬度

GPS坐标系及转换

将地理位置纬度和经度转换为数字格式?

如何在目标c中将gps北和gps西转换为纬度/经度

这是啥纬度/经度格式?

GPS模块输出的NMEA数据ddmm.mmmm转换成dd.ddddd并在google Earth Pro中描点