¿Expresión regular para hacer coincidir las coordenadas de latitud / longitud?

149

Estoy tratando de crear una expresión regular para hacer coincidir las coordenadas de latitud / longitud. Para hacer coincidir un número de doble precisión que he usado (\-?\d+(\.\d+)?), e intenté combinarlo en una sola expresión:

^(\-?\d+(\.\d+)?),\w*(\-?\d+(\.\d+)?)$

Esperaba que esto coincidiera con un doble, una coma, quizás algo de espacio y otro doble, pero no parece funcionar. Específicamente, solo funciona si NO hay espacio, ni uno ni más. ¿Qué he hecho mal?

Jake Petroules
fuente

Respuestas:

117

El espacio en blanco es \ s, no \ w

^(-?\d+(\.\d+)?),\s*(-?\d+(\.\d+)?)$

A ver si esto funciona

Eric C
fuente
1
Tuve que usar punto en lugar de coma: /^(\-?\d+(\.\d+)?) HereAdot. endMod \ s * (\ -? \ d + (\. \ d +)?) $ /
kolodi
Acepta valores fuera del rango permitido para lats y longs. 91,181
Arun Karunagath
Esto también funciona para las coordenadas x / y de los sistemas de referencia espacial proyectados
DeEgge
218

Éste coincidirá estrictamente con los valores de latitud y longitud que se encuentran dentro del rango correcto:

^[-+]?([1-8]?\d(\.\d+)?|90(\.0+)?),\s*[-+]?(180(\.0+)?|((1[0-7]\d)|([1-9]?\d))(\.\d+)?)$

Partidos

  • +90.0, -127.554334
  • 45, 180
  • -90, -180
  • -90.000, -180.0000
  • +90, +180
  • 47.1231231, 179.99999999

No coincide

  • -90., -180.
  • +90.1, -100.111
  • -91, 123,456
  • 045, 180
Iain Fraser
fuente
Esto es asombroso Felicitaciones por el rango de verificación de inclusión.
radj
1
Creo que tienes un error tipográfico en tu primer ejemplo de coincidencias. Dudo que el RegEx coincida con 3 valores.
Burkhard
Fijo. Estaba destinado a ser dos ejemplos separados.
Iain Fraser
77
Modificado para aceptar espacios en blanco en ambos lados de la coma: ^ [- +]? ([1-8]? \ D (\. \ D +)? | 90 (\. 0 +)?) \ S *, \ s * [- +]? (180 (\. 0 +)? | ((1 [0-7] \ d) | ([1-9]? \ d)) (\. \ d +)?) $
puddinman13
2
Cambié esto para obtener ese lat lat en los grupos de captura utilizando la ?:sintaxis del grupo de captura, así como la polaridad de captura(^[-+]?(?:[1-8]?\d(?:\.\d+)?|90(?:\.0+)?)),\s*([-+]?(?:180(?:\.0+)?|(?:(?:1[0-7]\d)|(?:[1-9]?\d))(?:\.\d+)?))$
narthur157
109

Estoy usando estos (formato decimal, con 6 dígitos decimales):

Latitud

^(\+|-)?(?:90(?:(?:\.0{1,6})?)|(?:[0-9]|[1-8][0-9])(?:(?:\.[0-9]{1,6})?))$

Visualización de la expresión regular de Latitude

Longitud

^(\+|-)?(?:180(?:(?:\.0{1,6})?)|(?:[0-9]|[1-9][0-9]|1[0-7][0-9])(?:(?:\.[0-9]{1,6})?))$

Longitud Visualización de expresiones regulares


Aquí hay una esencia que prueba ambos, reportados aquí también, para facilitar el acceso. Es una prueba Java TestNG. Necesitas Slf4j, Hamcrest y Lombok para ejecutarlo:

import static org.hamcrest.Matchers.*;
import static org.hamcrest.MatcherAssert.*;

import java.math.RoundingMode;
import java.text.DecimalFormat;

import lombok.extern.slf4j.Slf4j;

import org.testng.annotations.Test;

@Slf4j
public class LatLongValidationTest {

    protected static final String LATITUDE_PATTERN="^(\\+|-)?(?:90(?:(?:\\.0{1,6})?)|(?:[0-9]|[1-8][0-9])(?:(?:\\.[0-9]{1,6})?))$";
    protected static final String LONGITUDE_PATTERN="^(\\+|-)?(?:180(?:(?:\\.0{1,6})?)|(?:[0-9]|[1-9][0-9]|1[0-7][0-9])(?:(?:\\.[0-9]{1,6})?))$";

    @Test
    public void latitudeTest(){
        DecimalFormat df = new DecimalFormat("#.######");
        df.setRoundingMode(RoundingMode.UP);
        double step = 0.01;
        Double latitudeToTest = -90.0;

        while(latitudeToTest <= 90.0){
            boolean result = df.format(latitudeToTest).matches(LATITUDE_PATTERN);
            log.info("Latitude: tested {}. Result (matches regex): {}", df.format(latitudeToTest), result);
            assertThat(result, is(true));
            latitudeToTest += step;
        }

        latitudeToTest = -90.1;

        while(latitudeToTest >= -200.0){
            boolean result = df.format(latitudeToTest).matches(LATITUDE_PATTERN);
            log.info("Latitude: tested {}. Result (matches regex): {}", df.format(latitudeToTest), result);
            assertThat(result, is(false));
            latitudeToTest -= step;
        }

        latitudeToTest = 90.01;

        while(latitudeToTest <= 200.0){
            boolean result = df.format(latitudeToTest).matches(LATITUDE_PATTERN);
        log.info("Latitude: tested {}. Result (matches regex): {}", df.format(latitudeToTest), result);
            assertThat(result, is(false));
            latitudeToTest += step;
        }
    }

    @Test
    public void longitudeTest(){
        DecimalFormat df = new DecimalFormat("#.######");
        df.setRoundingMode(RoundingMode.UP);
        double step = 0.01;
        Double longitudeToTest = -180.0;

        while(longitudeToTest <= 180.0){
            boolean result = df.format(longitudeToTest).matches(LONGITUDE_PATTERN);
            log.info("Longitude: tested {}. Result (matches regex): {}", df.format(longitudeToTest), result);
            assertThat(result, is(true));
            longitudeToTest += step;
        }

        longitudeToTest = -180.01;

        while(longitudeToTest >= -300.0){
            boolean result = df.format(longitudeToTest).matches(LONGITUDE_PATTERN);
            log.info("Longitude: tested {}. Result (matches regex): {}", df.format(longitudeToTest), result);
            assertThat(result, is(false));
            longitudeToTest -= step;
        }

        longitudeToTest = 180.01;

        while(longitudeToTest <= 300.0){
            boolean result = df.format(longitudeToTest).matches(LONGITUDE_PATTERN);
            log.info("Longitude: tested {}. Result (matches regex): {}", df.format(longitudeToTest), result);
            assertThat(result, is(false));
            longitudeToTest += step;
        }
    }
}
Marco Ferrari
fuente
Esta fue una expresión regular muy agradable! ¿Pero es posible acortarlo un poco? :) Si no puede, está bien pero el código
abreviado
@ErikEdgren No encontré una manera de acortarlo :(
Marco Ferrari
1
Ok: / Oh bien. Tu expresión regular sigue siendo increíble;)
Airikr
2
buena visual: D ¡No sabía sobre este sitio web! Gracias !
Damiii
¿Cuál es el sitio web url
K? La toxicidad en SO está creciendo.
19

En realidad, Alix Axel, la expresión regular anterior es incorrecta en latitud, la longitud varía el punto de vista.

Las mediciones de latitud varían de –90 ° a + 90 ° Las mediciones de longitud varían de –180 ° a + 180 °

Por lo tanto, la expresión regular que figura a continuación se valida con mayor precisión.
Además, según mi pensamiento, nadie debería restringir el punto decimal en latitud / longitud.

^([-+]?\d{1,2}([.]\d+)?),\s*([-+]?\d{1,3}([.]\d+)?)$

O para el objetivo C

^([-+]?\\d{1,2}([.]\\d+)?),\\s*([-+]?\\d{1,3}([.]\\d+)?)$
Sampada
fuente
2
Se acepta 99para Latitude, mientras 99está fuera del intervalo de -90, +90por lo válido.
ako
14
^-?[0-9]{1,3}(?:\.[0-9]{1,10})?$

Desglose de expresiones regulares:

^-?[0-9]{1,3}(?:\.[0-9]{1,10})?$

-? # aceptar valores negativos

^ # Inicio de cadena

[0-9]{1,3} # Match 1-3 dígitos (es decir, 0-999)

(?: # Intenta hacer coincidir ...

\. # un punto decimal

[0-9]{1,10} # seguido de uno a 10 dígitos (es decir, 0-9999999999)

)? # ... opcionalmente

$ # Fin de cadena

Zehra Nasif
fuente
Creo que el tuyo es el más elegante. En primer lugar, funcionó de inmediato sin tener que editar y reemplazar los caracteres de escape. En segundo lugar, es corto. En tercer lugar, es fácil de entender.
Jim Rota
9

Prueba esto:

^(\()([-+]?)([\d]{1,2})(((\.)(\d+)(,)))(\s*)(([-+]?)([\d]{1,3})((\.)(\d+))?(\)))$

Compruébalo en:

http://regexpal.com/

Pegue la expresión en el cuadro superior, luego ponga cosas como esta en el cuadro inferior:

(80.0123, -34.034)
(80.0123)
(80.a)
(980.13, 40)
(99.000, 122.000)

Desglose de expresiones regulares:

^                    # The string must start this way (there can't be anything before). 
    (\()             # An opening parentheses (escaped with a backslash).
    ([-+]?)          # An optional minus, or an optional plus.
    ([\d]{1,2})      # 1 or 2 digits (0-9).
    (                # Start of a sub-pattern.
        (            # Start of a sub-pattern.
            (\.)     # A dot (escaped with a backslash).
            (\d+)    # One or more digits (0-9).
            (,)      # A comma.
        )            # End of a sub-pattern.
    )                # End of a sub-pattern.
    (\s*)            # Zero or more spaces.
    (                # Start of a sub-pattern.
        ([-+]?)      # An optional minus, or an optional plus. 
        ([\d]{1,3})  # 1 to 3 digits (0-9).
        (            # Start of a pattern.
            (\.)     # A dot (escaped with a backslash).
            (\d+)    # One or more digits (0-9).
        )?           # End of an optional pattern.
        (\))         # A closing parenthesis (escaped with a backkslash).
    )                # End of a pattern
$                    # The string must end this way (there can't be anything after).

Ahora, lo que NO hace es restringirse a este rango:

(-90 to +90, and -180 to +180)

En cambio, se limita a este rango:

(-99 to +99, -199 to +199) 

Pero el objetivo es principalmente dividir cada parte de la expresión.

usuario1439929
fuente
7

Aquí hay una versión más estricta:

^([-+]?\d{1,2}[.]\d+),\s*([-+]?\d{1,3}[.]\d+)$
  • Latitud = -90-+90
  • Longitud = -180-+180
Alix Axel
fuente
1
Creo que {1,2} debería venir primero, luego {1,3}
randunel
@Arjan: Corregido, siempre confundo los dos. ¡Gracias!
Alix Axel
5

Pitón:

Latitud: result = re.match("^[+-]?((90\.?0*$)|(([0-8]?[0-9])\.?[0-9]*$))", '-90.00001')

Longitud: result = re.match("^[+-]?((180\.?0*$)|(((1[0-7][0-9])|([0-9]{0,2}))\.?[0-9]*$))", '-0.0000')

Latitude debería fallar en el ejemplo.

picmate 涅
fuente
4

@ Macro-Ferrari. Encontré una manera de acortarlo, y sin mirar a la luz de todas las conversaciones recientes sobre motores regex

const LAT_RE = /^[+-]?(([1-8]?[0-9])(\.[0-9]{1,6})?|90(\.0{1,6})?)$/;

ingrese la descripción de la imagen aquí

const LONG_RE = /^[+-]?((([1-9]?[0-9]|1[0-7][0-9])(\.[0-9]{1,6})?)|180(\.0{1,6})?)$/;

ingrese la descripción de la imagen aquí

Arun Karunagath
fuente
Buena explicación, por cierto, ¿cómo conseguiste este control de flujo de cualquier software específico que utilizaste? este regexper.com ?
silentsudo
3

Creo que estás usando \ w (carácter de palabra) donde deberías estar usando \ s (espacio en blanco). Los caracteres de palabras generalmente consisten en [A-Za-z0-9_], por lo que excluye su espacio, que luego no coincide en el signo menos opcional o un dígito.

theraccoonbear
fuente
3

Esto funcionaría para un formato como este: 31 ͦ 37.4 'E

^[-]?\d{1,2}[ ]*ͦ[ ]*\d{1,2}\.?\d{1,2}[ ]*\x27[ ]*\w$
msaleh
fuente
1

Rubí

Longitud -179.99999999..180

/^(-?(?:1[0-7]|[1-9])?\d(?:\.\d{1,8})?|180(?:\.0{1,8})?)$/ === longitude.to_s

Latitud -89.99999999..90

/^(-?[1-8]?\d(?:\.\d{1,8})?|90(?:\.0{1,8})?)$/ === latitude.to_s
Zoran Kikic
fuente
0

Un método completo y simple en el objetivo C para verificar el patrón correcto de latitud y longitud es:

 -( BOOL )textIsValidValue:(NSString*) searchedString
{
    NSRange   searchedRange = NSMakeRange(0, [searchedString length]);
    NSError  *error = nil;
    NSString *pattern = @"^[-+]?([1-8]?\\d(\\.\\d+)?|90(\\.0+)?),\\s*[-+]?(180(\\.0+)?|((1[0-7]\\d)|([1-9]?\\d))(\\.\\d+)?)$";
    NSRegularExpression* regex = [NSRegularExpression regularExpressionWithPattern: pattern options:0 error:&error];
    NSTextCheckingResult *match = [regex firstMatchInString:searchedString options:0 range: searchedRange];
    return match ? YES : NO;
}

donde searchString es la entrada que el usuario ingresaría en el campo de texto respectivo.

saxenarishav
fuente
0

PHP

Aquí está la versión de PHP (los valores de entrada son: $latitudey $longitude):

$latitude_pattern  = '/\A[+-]?(?:90(?:\.0{1,18})?|\d(?(?<=9)|\d?)\.\d{1,18})\z/x';
$longitude_pattern = '/\A[+-]?(?:180(?:\.0{1,18})?|(?:1[0-7]\d|\d{1,2})\.\d{1,18})\z/x';
if (preg_match($latitude_pattern, $latitude) && preg_match($longitude_pattern, $longitude)) {
  // Valid coordinates.
}
kenorb
fuente
-1

Puedes probar esto:

var latExp = /^(?=.)-?((8[0-5]?)|([0-7]?[0-9]))?(?:\.[0-9]{1,20})?$/;
var lngExp = /^(?=.)-?((0?[8-9][0-9])|180|([0-1]?[0-7]?[0-9]))?(?:\.[0-9]{1,20})?$/;
Sagar Mal Shankhala
fuente
-2

Prueba esto:

^[-+]?(([0-8]\\d|\\d)(\\.\\d+)?|90(\\.0+)?)$,\s*^[-+]?((1[0-7]\\d(\\.\\d+)?)|(180(\\.0+)?)|(\\d\\d(\\.\\d+)?)|(\\d(\\.\\d+)?))$
jeremyvillalobos
fuente
-2

Prueba esto:

(?<!\d)([-+]?(?:[1-8]?\d(?:\.\d+)?|90(?:\.0+)?)),\s*([-+]?(?:180(?:\.0+)?|(?:(?:1[0-7]\d)|(?:[1-9]?\d))(?:\.\d+)?))(?!\d)`
usuario4325241
fuente
55
Las respuestas de código puro rara vez son una buena idea. Agregue un texto descriptivo a su respuesta.
timclutton
funciona muy bien: valida con precisión y selecciona lat, largo de cualquier texto circundante. Sin embargo, no limita el número de dígitos significativos que permite después del punto decimal.
user4325241