Extracting Coordinates with Regex from Google Maps URLs

2024-05-19
By: O Wolfson

In web development, dealing with URLs and extracting specific data from them is a common task. In this article, we'll explore how to use regular expressions (regex) to extract accurate coordinates from expanded Google Maps URLs. Specifically, we'll look at a utility function designed for this purpose.

The Utility Function

Here's the utility function that we'll dissect:

typescript
"use server";

import axios from "axios";

export const expandUrl = async (shortUrl: string): Promise<string | null> => {
  try {
    const response = await axios.get(shortUrl, {
      maxRedirects: 0,
      validateStatus: (status) => status === 302, // Handle redirect
    });
    return response.headers.location; // This contains the expanded URL
  } catch (error) {
    console.error("Error expanding URL:", error);
    return null;
  }
};

const dmsToDecimal = (
  degrees: number,
  minutes: number,
  seconds: number,
  direction: string
): number => {
  const decimal = degrees + minutes / 60 + seconds / 3600;
  return direction === "S" || direction === "W" ? -decimal : decimal;
};

export const extractLatLong = (
  url: string
): { lat: number; lng: number } | null => {
  const decodedUrl = decodeURIComponent(url);

  const dmsPattern = /(\d{1,3})°(\d{1,2})'(\d{1,2}(?:\.\d+)?)"?([NSEW])/g;
  const decimalPattern = /@(-?\d+\.\d+),(-?\d+\.\d+)/;
  const accurateDecimalPattern = /3d(-?\d+\.\d+)!4d(-?\d+\.\d+)/;

  let match;
  let lat, lng;

  match = accurateDecimalPattern.exec(decodedUrl);
  if (match) {
    return {
      lat: parseFloat(match[1]),
      lng: parseFloat(match[2]),
    };
  }

  const dmsMatches = decodedUrl.match(dmsPattern);
  if (dmsMatches && dmsMatches.length >= 2) {
    const latMatch = dmsMatches[0].match(
      /(\d{1,3})°(\d{1,2})'(\d{1,2}(?:\.\d+)?)"?([NSEW])/
    );
    const lngMatch = dmsMatches[1].match(
      /(\d{1,3})°(\d{1,2})'(\d{1,2}(?:\.\d+)?)"?([NSEW])/
    );

    if (latMatch && lngMatch) {
      lat = dmsToDecimal(
        parseInt(latMatch[1]),
        parseInt(latMatch[2]),
        parseFloat(latMatch[3]),
        latMatch[4]
      );
      lng = dmsToDecimal(
        parseInt(lngMatch[1]),
        parseInt(lngMatch[2]),
        parseFloat(lngMatch[3]),
        lngMatch[4]
      );

      return { lat, lng };
    }
  }

  match = decimalPattern.exec(decodedUrl);
  if (match) {
    return {
      lat: parseFloat(match[1]),
      lng: parseFloat(match[2]),
    };
  }

  return null;
};

Understanding the Regex Patterns

  1. Accurate Decimal Coordinates Pattern

    javascript
    const accurateDecimalPattern = /3d(-?\d+\.\d+)!4d(-?\d+\.\d+)/;
    
    • 3d and 4d: These are part of the URL structure that indicate 3D and 4D map coordinates.
    • (-?\d+\.\d+): This matches the latitude and longitude. It allows for optional negative signs (-?), followed by one or more digits (\d+), a decimal point (\.), and one or more digits after the decimal point.

    This pattern is used to extract the most accurate coordinates directly from the URL.

  2. DMS (Degrees, Minutes, Seconds) Coordinates Pattern

    javascript
    const dmsPattern = /(\d{1,3})°(\d{1,2})'(\d{1,2}(?:\.\d+)?)"?([NSEW])/g;
    
    • (\d{1,3})°: Matches degrees, which can be 1 to 3 digits followed by a degree symbol (°).
    • (\d{1,2})': Matches minutes, which can be 1 to 2 digits followed by a single quote (').
    • (\d{1,2}(?:\.\d+)?)"?: Matches seconds, which can be 1 to 2 digits, optionally followed by a decimal point and more digits, followed by an optional double quote ("?).
    • ([NSEW]): Matches the direction (North, South, East, West).

    This pattern is used to extract DMS coordinates from the URL, which are then converted to decimal format.

  3. Decimal Coordinates Pattern

    javascript
    const decimalPattern = /@(-?\d+\.\d+),(-?\d+\.\d+)/;
    
    • @: Matches the @ symbol in the URL, which precedes the coordinates.
    • (-?\d+\.\d+),(-?\d+\.\d+): Matches the latitude and longitude in decimal format, similar to the previous pattern.

    This pattern is used as a fallback to extract decimal coordinates directly from the URL.

Example URL

Here is an example Google Maps link for Transamerica Pyramid in San Francisco, California. The URL is as follows:

https://www.google.com/maps/place/Transamerica+Pyramid/@37.7951775,-122.4053536,17z/data=!3m1!5s0x8085808a5dc66e05:0x9639fb0efcc94595!4m15!1m8!3m7!1s0x8085808ac13be543:0x65487a1b70f0a878!2sTransamerica+Pyramid!8m2!3d37.7951775!4d-122.4027787!10e1!16zL20vMGdqZHI!3m5!1s0x8085808ac13be543:0x65487a1b70f0a878!8m2!3d37.7951775!4d-122.4027787!16zL20vMGdqZHI?entry=ttu

Test the Regex Pattern

Let's test the regex pattern to ensure it can extract the correct coordinates from the URL. We will extract the accurate decimal coordinates 37.7951775 (latitude) and -122.4027787 (longitude) from the example URL.

You can test the regular expressions at regex101.

Try adding the url above to the TEST STRING input at Regex 101. Then paste this expression 3d(-?\d+\.\d+)!4d(-?\d+\.\d+) in the REGULAR EXPRESSION field, and see the magic. The coordinates extracted from the URL should provide accurate latitude and longitude values that can be used in your application.

Matches

plaintext
37.7951775 // Latitude
-122.4027787 // Longitude

Conclusion

Regular expressions are powerful tools for extracting specific data from strings, such as URLs. In this utility function, we used regex to accurately extract latitude and longitude coordinates from Google Maps URLs. Understanding and utilizing these patterns can greatly enhance the flexibility and functionality of your web applications.

Feel free to explore the demo and try out different Google Maps links to see the regex in action.

Check out this article on regex.