converting GPS latitude/longitude from different formats to one format (in PHP)
i'm trying to built in support for locations in my application and i'm expecting users to be inputting gps coordinates in a variety of ways. I need to convert all of the below to: latitude - direction (N/s), degres, minutes, seconds; longitude (E/W) - degrees, minuts, seconds.
Note, each 开发者_如何学Cuser input will be in a single line. I would like my users to input only in one single way, but ppl will definitely enter as one of the following...:
eg: 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] may be a single space as well...
The final format needs to beas:
latitude.direction = south latitude.degrees = 21 latitude.minutes = 16 latitude.seconds = 674 longitude.direction = east longitude.degrees = 27 longitude.minutes = 30 longitude.seconds = 318(a) what is the simplest way of asking ordinary-non-tech users to input the GPS coordinate?s
(b) how do i convert the above to the final format? any built in functions that handle these variations in data input?i've seen GPS format in PHP - but i need to handle a more varied input.
I have been working around with this further (and I notice that you edited your question).
A) What is the simplest way of asking ordinary-non-tech users to input the GPS coordinates?
The simplest, and most user friendly fashion for getting non-tech users to enter details would be using Google Maps. This would allow for you to use the Google Geocoder to parse their input (and provide a more standardised and formatted output). Further, if the location the user is inputting is their current location, you could look at using the Geolocation functionality offered by some of the modern browsers.
B) How do i convert the above to the final format? Any built in functions that handle these variations in data input?
Based on your test data, I have formulated a PHP Regular Expression to parse it and return a predictable and standardised output.
$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
}
}
Outputs:
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)
)
Example:
// 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]=> ""
)
You could then, subsequently, process the results of the Regular Expression, to produce a float for the Lat/Long link so:
// (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);
Which produces:
// 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
I think the best way would be to restrict user input as much as possible, so that they may only enter valid data. Have the user separate the data in tokens for you, instead of you trying to account for every single possibility. Use as many textboxes/drop downs/etc as necessary to force the user to populate the data correctly. I think it would be desirable to minimize the amount & variations of text parsing you will be doing.
What format do the users get their data in? If it is just a decimal lat/long e.g(50.32,123.55) then just simply have two numerical inputs they can fill out, and possibly include an example value in the box. If the users get their data in degree/minute/second format then have exactly these fields that they need to fill out for each latitude and longitude. If you allow for both decimal & degree representations it should cover all your users.
Have as many inputs as needed to break down the data in enough tokens that ensures consistency when interpreting it in your program!
EDIT: A funky idea if you find it acceptable for your site would be to have a Google Map where the user drags a marker to their desired location. You can then get the GPS coordinates in a consistent manner from that marker, and use that for whatever further work you need to do!
- split latitude and longitude, using explode() or preg_split().
- For both latitude and longitude, determine if it is given as a float or with minutes.
- Convert the value to degrees (as float)
Your best (but, admittedly, least guaranteed) method is to drive user behaviour to try and have them format the data in a standardised and easily parsed format. Even just having one or two easy main formats to try and encourage them to convert to would be an excellent step and reduce the amount of error correction/formatting required.
Beyond that, I would suggest that creating Regular Expressions, and functions behind those RegExps to standardise the data you are going to use would be a solution.
I have run a few RegExps against the test data you have provided, but am having trouble creating a bulletproof solution in that regard (it may be that you will need to have a few different patterns to pick up each combination).
I have even tried parsing some of the test data provided through the Google Geocoding API (which is, normally, quite a resilient system, allowing for plain text addressing, as well as multiple Lat/Long formats), but, no joy.
The more standard the data coming in, the easier to create accurate information coming out. Maybe integrating a map (Google Maps or otherwise) into the input phase would allow for you to validate the input more accurately.
精彩评论