Expressão regular para correspondência de coordenadas de latitude / longitude?

149

Estou tentando criar uma expressão regular para combinar as coordenadas de latitude / longitude. Para combinar um número de precisão dupla que usei (\-?\d+(\.\d+)?), tentei combinar isso em uma única expressão:

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

Eu esperava que isso correspondesse a um duplo, uma vírgula, talvez algum espaço e outro duplo, mas não parece funcionar. Especificamente, só funciona se não houver espaço, não um ou mais. O que eu fiz errado?

Jake Petroules
fonte

Respostas:

117

Espaço em branco é \ s, não \ w

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

Veja se isso funciona

Eric C
fonte
1
Eu tive que usar ponto em vez de vírgula: /^(\-?\d+(\.\d+)?) HereAdot. endMod \ s * (\ -?. \ d + (\ \ d +)?) $ /
kolodi
Ele aceita valores fora do intervalo permitido para lats e longs. por exemplo, 91.181
Arun Karunagath
Isto funciona para x / y-coordenadas de sistemas espaciais de referência projectado, bem
DeEgge
218

Este corresponderá estritamente aos valores de latitude e longitude que estão dentro do intervalo correto:

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

Partidas

  • +90,0, -127,554334
  • 45, 180
  • -90, -180
  • -90.000, -180.0000
  • +90, +180
  • 47.1231231, 179.99999999

Não corresponde

  • -90., -180.
  • +90.1, -100.111
  • -91, 123,456
  • 045, 180
Iain Fraser
fonte
Isso é incrível. Parabéns pela inclusão de verificação de intervalo.
radj
1
Eu acho que você tem um erro de digitação no seu primeiro exemplo de correspondências. Duvido que o RegEx corresponda a 3 valores.
Burkhard
Fixo. Era para ser dois exemplos separados.
Iain Fraser
7
Modificado para aceitar o espaço em branco nos dois lados da vírgula: ^ [- +]? ([1-8]? \ D (\. \ D +)? | 90 (\. 0 +)?) \ S *, \ s * [- +]? (180 (\. 0 +)? | ((1 [0-7] \ d) | ([1-9]? \ d)) (\. \ d +)?) $
Veja o que você precisa
2
Eu mudei isso para obter exatamente isso lon lat nos grupos de captura usando a ?:sintaxe non grupo de captura, bem como captura de polaridade(^[-+]?(?:[1-8]?\d(?:\.\d+)?|90(?:\.0+)?)),\s*([-+]?(?:180(?:\.0+)?|(?:(?:1[0-7]\d)|(?:[1-9]?\d))(?:\.\d+)?))$
narthur157
109

Estou usando esses (formato decimal, com 6 dígitos decimais):

Latitude

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

Visualização de expressões regulares do Latitude

Longitude

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

Longitude Visualização de expressões regulares


Aqui está uma essência que testa ambos, relatados aqui também, para facilitar o acesso. É um teste Java TestNG. Você precisa do Slf4j, Hamcrest e Lombok para executá-lo:

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
fonte
Este foi um regex muito bom! Mas é possível reduzi-lo um pouco? :) Se não puder, é código okey mas encurtar são sempre bem-vindos :)
Airikr
@ErikEdgren Eu não encontrei uma maneira de reduzi-lo :( #
Marco Ferrari
1
Ok: / Oh bem. Seu regex ainda é incrível;)
Airikr
2
visual agradável: D Não sabia sobre este site! Obrigado !
Damiii
Qual é o URL do site
K - A toxicidade no SO está crescendo.
19

Na verdade, Alix Axel, acima do regex, está errado na latitude, o ponto de vista das faixas de longitude.

As medidas de latitude variam de –90 ° a + 90 ° As medidas de latitude variam de –180 ° a + 180 °

Portanto, o regex fornecido abaixo valida com mais precisão.
Além disso, conforme meu pensamento, ninguém deve restringir o ponto decimal em latitude / longitude.

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

OU para o objetivo C

^([-+]?\\d{1,2}([.]\\d+)?),\\s*([-+]?\\d{1,3}([.]\\d+)?)$
Sampada
fonte
2
Ele aceita 99por Latitude, enquanto 99está fora do intervalo de -90, +90e assim inválido.
ako
14
^-?[0-9]{1,3}(?:\.[0-9]{1,10})?$

Repartição do Regex:

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

-? # aceitar valores negativos

^ # Início da string

[0-9]{1,3} # Corresponde a 1-3 dígitos (ou seja, 0-999)

(?: # Tente combinar ...

\. # um ponto decimal

[0-9]{1,10} # seguido de um a 10 dígitos (ou seja, 0-9999999999)

)? # ... opcionalmente

$ # Fim da string

Zehra Nasif
fonte
Eu acho que o seu é o mais elegante. Em primeiro lugar, funcionou imediatamente sem precisar editar e substituir caracteres de escape. Em segundo lugar, é curto. Em terceiro lugar, é fácil de entender.
Jim Rota
9

Tente o seguinte:

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

Confira em:

http://regexpal.com/

Cole a expressão na caixa superior e coloque coisas como esta na caixa inferior:

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

Repartição do Regex:

^                    # 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).

Agora, o que isso NÃO faz é restringir-se a esse intervalo:

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

Em vez disso, ele se restringe a esse intervalo:

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

Mas o ponto principal é apenas dividir cada pedaço da expressão.

user1439929
fonte
7

Aqui está uma versão mais rigorosa:

^([-+]?\d{1,2}[.]\d+),\s*([-+]?\d{1,3}[.]\d+)$
  • Latitude = -90-+90
  • Longitude = -180-+180
Alix Axel
fonte
1
Acredito que {1,2} deve vir em primeiro lugar, em seguida, {1,3}
randunel
@ Arjan: Corrigido, eu sempre confundo os dois. Obrigado!
Alix Axel
5

Pitão:

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

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

O Latitude deve falhar no exemplo.

picmate 涅
fonte
4

@ macro-ferrari Eu encontrei uma maneira de reduzi-lo, e sem olhar para o futuro, à luz de todas as conversas recentes sobre mecanismos regex

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

insira a descrição da imagem aqui

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

insira a descrição da imagem aqui

Arun Karunagath
fonte
Boa explicação, como você conseguiu esse controle de fluxo de qualquer software específico usado? este regexper.com ?
silentsudo
3

Acredito que você esteja usando \ w (caractere de palavra) onde deveria estar usando \ s (espaço em branco). Os caracteres do Word normalmente consistem em [A-Za-z0-9_], de modo que exclui seu espaço, que falha ainda mais na correspondência no sinal de menos opcional ou em um dígito.

theraccoonbear
fonte
3

Isso funcionaria para um formato como este: 31 ͦ 37.4 'E

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

Rubi

Longitude -179.99999999..180

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

Latitude -89.99999999..90

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

Um método completo e simples no objetivo C para verificar o padrão correto de latitude e longitude é:

 -( 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;
}

em que seekString é a entrada que o usuário digitaria no respectivo campo de texto.

saxenarishav
fonte
0

PHP

Aqui está a versão do PHP (os valores de entrada são: $latitudee $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
fonte
-1

Você pode tentar isso:

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
fonte
-2

Tente o seguinte:

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

Tente o seguinte:

(?<!\d)([-+]?(?:[1-8]?\d(?:\.\d+)?|90(?:\.0+)?)),\s*([-+]?(?:180(?:\.0+)?|(?:(?:1[0-7]\d)|(?:[1-9]?\d))(?:\.\d+)?))(?!\d)`
user4325241
fonte
5
Respostas de código puro raramente são uma boa ideia. Por favor, adicione algum texto descritivo à sua resposta.
timclutton
funciona muito bem: valida com precisão e seleciona lat, muito tempo de qualquer texto ao redor. No entanto, não limita o número de dígitos significativos permitido após o ponto decimal.
user4325241