Matching GPS Coordinates with Regex
Latitude and longitude form the address system of every place on Earth. Latitude runs from -90° at the South Pole to +90° at the North Pole. Longitude runs from -180° to +180° around the globe, with 0° at Greenwich. GPS devices, mapping APIs, geotagged photos, and delivery logistics all rely on the same decimal-degrees format — usually with 5–7 decimal places (about 1 metre of precision at 6 decimals). Regex is the fastest way to catch typos and out-of-range values before they hit your map or database. Below are the patterns that correctly enforce the -90/+90 and -180/+180 ranges, plus edge cases most tutorials miss.
The Core Patterns
Latitude — strict range check
/^-?([1-8]?\d(\.\d+)?|90(\.0+)?)$/
// Matches: 0 40.7128 -34.6037 89.9999 90 -90 90.0
// Rejects: 91 -95 90.5 abc
// Two alternations handle 0-89.9... AND exactly 90.The [1-8]?\\d matches 0-89. The optional (\\.\\d+)? allows any decimal precision. The 90(\\.0+)? alternative catches exact 90 with any trailing zeros (90, 90.0, 90.000). Without the alternation, 91 would slip through.
Longitude — strict range check
/^-?(1[0-7]\d(\.\d+)?|180(\.0+)?|\d{1,2}(\.\d+)?)$/
// Matches: 0 74.0060 -122.4194 179.999 180 -180
// Rejects: 181 -185 180.5 abc
// Three alternations: 100-179, exact 180, and 0-99.Coordinate pair — "lat,lng"
/^(-?([1-8]?\d(\.\d+)?|90(\.0+)?))\s*,\s*(-?(1[0-7]\d(\.\d+)?|180(\.0+)?|\d{1,2}(\.\d+)?))$/
// Matches: "40.7128,-74.0060" "40.7128, -74.0060" "0,0"
// The \s* allows optional spaces around the comma.Loose format (range check separately)
// Simple format regex — validate range in code afterwards
/^-?\d{1,3}(\.\d+)?$/
// Matches ANY number that looks like coordinates.
// Then in code: const n = parseFloat(str); if (n >= -90 && n <= 90) ...
// Trades regex complexity for code clarity — often better for maintenance.DMS format (Degrees Minutes Seconds)
/^(\d{1,3})°(\d{1,2})[′'](\d{1,2}(\.\d+)?)[″"]?\s?([NSEW])$/
// Matches: 40°42′46″N 40°42'46"N 74°00'22"W
// Group 1 = degrees, 2 = minutes, 3 = seconds, 5 = direction.
// Convert to decimal: (deg + min/60 + sec/3600) * (N/E ? 1 : -1)Precision-constrained (6 decimal places = ~11 cm)
// Latitude with max 6 decimals
/^-?([1-8]?\d(\.\d{1,6})?|90(\.0{1,6})?)$/
// Rejects 40.71284567 (too precise for most uses).Language-Specific Usage
JavaScript
const LAT = /^-?([1-8]?\d(\.\d+)?|90(\.0+)?)$/;
const LNG = /^-?(1[0-7]\d(\.\d+)?|180(\.0+)?|\d{1,2}(\.\d+)?)$/;
function isValidCoord(lat, lng) {
return LAT.test(String(lat)) && LNG.test(String(lng));
}
// Simpler alternative — format loose, range check in code
function isValidCoordSimple(lat, lng) {
const la = parseFloat(lat);
const ln = parseFloat(lng);
return Number.isFinite(la) && Number.isFinite(ln)
&& la >= -90 && la <= 90
&& ln >= -180 && ln <= 180;
}
// Parse a coordinate pair from a string
function parseCoords(str) {
const m = str.match(/^(-?\d+(?:\.\d+)?)\s*,\s*(-?\d+(?:\.\d+)?)$/);
if (!m) return null;
return { lat: parseFloat(m[1]), lng: parseFloat(m[2]) };
}
isValidCoord(40.7128, -74.0060); // true (New York)
isValidCoord(91, 0); // false
parseCoords('40.7128, -74.0060'); // { lat: 40.7128, lng: -74.0060 }Python
import re
LAT = re.compile(r'^-?([1-8]?\d(\.\d+)?|90(\.0+)?)$')
LNG = re.compile(r'^-?(1[0-7]\d(\.\d+)?|180(\.0+)?|\d{1,2}(\.\d+)?)$')
def is_valid_coord(lat, lng) -> bool:
return bool(LAT.match(str(lat))) and bool(LNG.match(str(lng)))
# Range check in code — often clearer
def is_valid_coord_simple(lat, lng) -> bool:
try:
la, ln = float(lat), float(lng)
return -90 <= la <= 90 and -180 <= ln <= 180
except (TypeError, ValueError):
return False
is_valid_coord(40.7128, -74.0060) # True
is_valid_coord(91, 0) # FalsePHP
function isValidLat(string $lat): bool {
return (bool) preg_match(
'/^-?([1-8]?\d(\.\d+)?|90(\.0+)?)$/',
$lat
);
}
function isValidLng(string $lng): bool {
return (bool) preg_match(
'/^-?(1[0-7]\d(\.\d+)?|180(\.0+)?|\d{1,2}(\.\d+)?)$/',
$lng
);
}
// Or the simpler range-check approach
function isValidCoord(float $lat, float $lng): bool {
return $lat >= -90 && $lat <= 90 && $lng >= -180 && $lng <= 180;
}Common Pitfalls
0,0 is Null Island
The coordinate (0, 0) is technically valid — it points to a spot in the Atlantic Ocean off the coast of Africa, nicknamed Null Island. In practice, many datasets have 0,0 because a coordinate was missing and defaulted to zero. If your app displays user locations, treat 0,0 as suspect and require explicit user confirmation.
lat,lng vs lng,lat — order matters
Most human-readable formats use lat, lng (Google Maps URL format). But GeoJSON reverses the order: [lng, lat]. PostGIS uses ST_MakePoint(lng, lat). Never assume — always check the documentation for the specific API you're using. Silent swap of order is one of the most common geo bugs in production.
Storing as string loses precision
If you regex-validate a string then store it as VARCHAR, comparison and range queries will not work. Store as DECIMAL(9,6) for lat and DECIMAL(10,6) for lng — this gives ~11 cm precision and enables geospatial indexes.
Float precision issues
IEEE 754 double-precision floats have 15–17 significant digits — more than enough for GPS. But 32-bit floats have only 7 digits, meaning ~1 metre error at world scale. Never store coordinates as FLOAT or REAL — use DOUBLE PRECISION or DECIMAL.
Antimeridian wraparound
180 and -180 refer to the same meridian (International Date Line). If your app does distance calculations, you must handle the wraparound: a route from 179°E to -179°E is 2° apart, not 358°. Use libraries like Turf.js or PostGIS ST_Distance_Sphere that handle this correctly.
Coordinate Regex Cheatsheet
| Goal | Pattern | Range |
|---|---|---|
| Latitude | /^-?([1-8]?\d(\.\d+)?|90(\.0+)?)$/ | -90 to +90 |
| Longitude | /^-?(1[0-7]\d(\.\d+)?|180(\.0+)?|\d{1,2}(\.\d+)?)$/ | -180 to +180 |
| Loose format | /^-?\d{1,3}(\.\d+)?$/ | check in code |
| Coord pair | /^-?\d+(?:\.\d+)?\s*,\s*-?\d+(?:\.\d+)?$/ | "lat,lng" |
| DMS format | /^\d+°\d+[′']\d+(\.\d+)?[″"]?[NSEW]$/ | 40°42′46″N |
Testing Your Coordinate Regex
Use the live Regex Tester above with these test strings:
- Match (real cities):
40.7128, -74.0060(New York),-33.8688, 151.2093(Sydney),51.5074, -0.1278(London) - Match (edge):
90, 180,-90, -180,0, 0 - Reject (out of range):
91, 0,0, 181,-95, 200 - Reject (bad format):
abc,40, 74, 100(3 numbers) - DMS:
40°42′46″N,74°00′22″W
Common Mistakes When Writing Coordinate Regex
- Using
\\d+for degrees. Accepts 999 as a valid latitude. Always enforce the range with alternations OR do a follow-up numeric range check in code. - Missing the minus sign.Half of the world's coordinates are negative (Southern Hemisphere, Western Hemisphere). Always allow
-?at the start. - Confusing lat/lng order. GeoJSON uses
[lng, lat]. Google Maps useslat,lng. PostGISST_MakePoint(lng, lat). Read the docs. - Trusting user-entered coordinates blindly. A well-formed pair could still be nonsense (0,0 = Null Island). Reverse-geocode to sanity-check.
- Storing as string.Prevents indexing, breaks range queries, and doesn't catch precision loss. Use
DECIMALorGEOGRAPHYcolumn types.
Performance Notes
Coordinate regexes have bounded quantifiers with a few alternations — they run in constant time even on invalid input. You can validate hundreds of thousands of coordinates per second. For batch geocoding pipelines, precompile the regex once and reuse. If you have millions of coordinates, the simple parseFloat + range check approach is measurably faster than regex — but for form validation the difference is imperceptible.