]> git.openstreetmap.org Git - rails.git/commitdiff
Parse lat and lon independently when using dms notation
authorAnton Khorev <tony29@yandex.ru>
Sat, 13 Jul 2024 14:40:01 +0000 (17:40 +0300)
committerAnton Khorev <tony29@yandex.ru>
Sat, 13 Jul 2024 14:52:39 +0000 (17:52 +0300)
app/controllers/geocoder_controller.rb
test/controllers/geocoder_controller_test.rb

index 3127622166a02a69e731fe384bcd10741128f5fb..02ebc8a1bccb565796a62cafb911bbd7bdd17647 100644 (file)
@@ -206,13 +206,9 @@ class GeocoderController < ApplicationController
     if query = params[:query]
       query.strip!
 
-      if latlon = query.match(/^(?<ns>[NS])\s*(?<nsd>\d{1,3}(?:\.\d+)?)°?\W*(?<ew>[EW])\s*(?<ewd>\d{1,3}(?:\.\d+)?)°?$/) ||                                                                                                     # [NSEW] decimal degrees
-                  query.match(/^(?<nsd>\d{1,3}(?:\.\d+)?)°?\s*(?<ns>[NS])\W*(?<ewd>\d{1,3}(?:\.\d+)?)°?\s*(?<ew>[EW])$/) ||                                                                                                     # decimal degrees [NSEW]
-                  query.match(/^(?<ns>[NS])\s*(?<nsd>\d{1,3})°?(?:\s*(?<nsm>\d{1,3}(?:\.\d+)?)['′]?)\W*(?<ew>[EW])\s*(?<ewd>\d{1,3})°?(?:\s*(?<ewm>\d{1,3}(?:\.\d+)?)['′]?)$/) ||                                               # [NSEW] degrees, decimal minutes
-                  query.match(/^(?<nsd>\d{1,3})°?(?:\s*(?<nsm>\d{1,3}(?:\.\d+)?)['′]?)\s*(?<ns>[NS])\W*(?<ewd>\d{1,3})°?(?:\s*(?<ewm>\d{1,3}(?:\.\d+)?)['′]?)\s*(?<ew>[EW])$/) ||                                               # degrees, decimal minutes [NSEW]
-                  query.match(/^(?<ns>[NS])\s*(?<nsd>\d{1,3})°?\s*(?<nsm>\d{1,2})['′]?(?:\s*(?<nss>\d{1,3}(?:\.\d+)?)["″]?)\W*(?<ew>[EW])\s*(?<ewd>\d{1,3})°?\s*(?<ewm>\d{1,2})['′]?(?:\s*(?<ews>\d{1,3}(?:\.\d+)?)["″]?)$/) || # [NSEW] degrees, minutes, decimal seconds
-                  query.match(/^(?<nsd>\d{1,3})°?\s*(?<nsm>\d{1,2})['′]?(?:\s*(?<nss>\d{1,3}(?:\.\d+)?)["″]?)\s*(?<ns>[NS])\W*(?<ewd>\d{1,3})°?\s*(?<ewm>\d{1,2})['′]?(?:\s*(?<ews>\d{1,3}(?:\.\d+)?)["″]?)\s*(?<ew>[EW])$/)    # degrees, minutes, decimal seconds [NSEW]
-        params.merge!(to_decdeg(latlon.named_captures)).delete(:query)
+      if latlon = query.match(/^(?<ns>[NS])\s*#{dms_regexp('ns')}\W*(?<ew>[EW])\s*#{dms_regexp('ew')}$/) ||
+                  query.match(/^#{dms_regexp('ns')}\s*(?<ns>[NS])\W*#{dms_regexp('ew')}\s*(?<ew>[EW])$/)
+        params.merge!(to_decdeg(latlon.named_captures.compact)).delete(:query)
 
       elsif latlon = query.match(%r{^(?<lat>[+-]?\d+(?:\.\d+)?)(?:\s+|\s*[,/]\s*)(?<lon>[+-]?\d+(?:\.\d+)?)$})
         params.merge!(:lat => latlon["lat"], :lon => latlon["lon"]).delete(:query)
@@ -224,6 +220,14 @@ class GeocoderController < ApplicationController
     params.permit(:query, :lat, :lon, :latlon_digits, :zoom, :minlat, :minlon, :maxlat, :maxlon)
   end
 
+  def dms_regexp(name_prefix)
+    /
+      (?: (?<#{name_prefix}d>\d{1,3}(?:\.\d+)?)°? ) |
+      (?: (?<#{name_prefix}d>\d{1,3})°?\s*(?<#{name_prefix}m>\d{1,2}(?:\.\d+)?)['′]? ) |
+      (?: (?<#{name_prefix}d>\d{1,3})°?\s*(?<#{name_prefix}m>\d{1,2})['′]?\s*(?<#{name_prefix}s>\d{1,2}(?:\.\d+)?)["″]? )
+    /x
+  end
+
   def to_decdeg(captures)
     ns = captures.fetch("ns").casecmp("s").zero? ? -1 : 1
     nsd = BigDecimal(captures.fetch("nsd", "0"))
index 4d5d345c3189327df6a9afc5e982d99c23a020f2..5ea02f76d2261af73025f00ebaf1426bb630e9e7 100644 (file)
@@ -261,6 +261,17 @@ class GeocoderControllerTest < ActionDispatch::IntegrationTest
     end
   end
 
+  #
+  # Test identification of lat/lon pairs with mixed precision
+  def test_identify_latlon_ne_mixed_precision
+    latlon_check "N1 5 E15",    1.083333, 15
+    latlon_check "N1 5 9 E15",  1.085833, 15
+    latlon_check "N1 5 9 E1 5", 1.085833, 1.083333
+    latlon_check "N15 E1 5",    15, 1.083333
+    latlon_check "N15 E1 5 9",  15, 1.085833
+    latlon_check "N1 5 E1 5 9", 1.083333, 1.085833
+  end
+
   #
   # Test identification of lat/lon pairs with values close to zero
   def test_identify_latlon_close_to_zero