Expression régulière pour faire correspondre les coordonnées de latitude / longitude?

149

J'essaie de créer une expression régulière pour faire correspondre les coordonnées de latitude / longitude. Pour faire correspondre un nombre à double précision que j'ai utilisé (\-?\d+(\.\d+)?), et j'ai essayé de le combiner en une seule expression:

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

Je m'attendais à ce que cela corresponde à un double, une virgule, peut-être un espace et un autre double, mais cela ne semble pas fonctionner. Plus précisément, cela ne fonctionne que s'il n'y a PAS d'espace, pas un ou plusieurs. Qu'est ce que j'ai mal fait?

Jake Petroules
la source

Réponses:

117

L'espace blanc est \ s, pas \ w

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

Voyez si cela fonctionne

Eric C
la source
1
J'ai dû utiliser un point au lieu de la virgule: /^(\-?\d+(\.\d+)?) HereAdot. endMod \ s * (\ -? \ d + (\. \ d +)?) $ /
kolodi
Il accepte des valeurs en dehors de la plage autorisée pour les lats et les longs. par exemple, 91,181
Arun Karunagath
Cela fonctionne également pour les coordonnées x / y des systèmes de référence spatiale projetés
DeEgge
218

Celui-ci correspondra strictement aux valeurs de latitude et de longitude comprises dans la plage correcte:

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

Allumettes

  • +90,0, -127,554334
  • 45, 180
  • -90, -180
  • -90 000, -180,0000
  • +90, +180
  • 47.1231231, 179.99999999

Ne correspond pas

  • -90., -180.
  • +90.1, -100.111
  • -91, 123,456
  • 045, 180
Iain Fraser
la source
C'est génial. Félicitations pour l'inclusion du contrôle de plage.
radj
1
Je pense que vous avez une faute de frappe dans votre premier exemple de matchs. Je doute que le RegEx corresponde à 3 valeurs.
Burkhard
Fixé. Il s'agissait de deux exemples distincts.
Iain Fraser
7
Modifié pour accepter les espaces blancs des deux côtés de la virgule: ^ [- +]? ([1-8]? \ D (\. \ D +)? | 90 (\. 0 +)?) \ S *, \ s * [- +]? (180 (\. 0 +)? | ((1 [0-7] \ d) | ([1-9]? \ d)) (\. \ d +)?) $
puddinman13
2
J'ai changé cela pour obtenir juste cette lat lon dans les groupes de capture en utilisant la ?:syntaxe de groupe non capturant, ainsi que la polarité de capture(^[-+]?(?:[1-8]?\d(?:\.\d+)?|90(?:\.0+)?)),\s*([-+]?(?:180(?:\.0+)?|(?:(?:1[0-7]\d)|(?:[1-9]?\d))(?:\.\d+)?))$
narthur157
109

J'utilise ceux-ci (format décimal, avec 6 chiffres décimaux):

Latitude

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

Visualisation des expressions régulières Latitude

Longitude

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

Visualisation des expressions régulières de longitude


Voici un résumé qui teste les deux, rapportés ici également, pour la facilité d'accès. C'est un test Java TestNG. Vous avez besoin de Slf4j, Hamcrest et Lombok pour l'exécuter:

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
la source
C'était une très belle regex! Mais est-il possible de le raccourcir un peu? :) Si ce n'est pas le cas, ça va mais le code raccourci est toujours le bienvenu :)
Airikr
@ErikEdgren je n'ai pas trouvé de moyen de le raccourcir :(
Marco Ferrari
1
Ok: / Oh bien. Votre regex est toujours géniale;)
Airikr
2
joli visuel: D Je ne connaissais pas ce site! Je vous remercie !
Damiii
Quelle est l'url du site Web
K - La toxicité dans le SO augmente.
19

En fait, Alix Axel, au-dessus de regex, est fausse en latitude et en longitude.

Les mesures de latitude vont de –90 ° à + 90 ° Les mesures de longitude vont de –180 ° à + 180 °

Ainsi, l'expression régulière donnée ci-dessous valide plus précisément.
De plus, selon ma pensée, personne ne devrait restreindre la virgule décimale en latitude / longitude.

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

OU pour l'objectif C

^([-+]?\\d{1,2}([.]\\d+)?),\\s*([-+]?\\d{1,3}([.]\\d+)?)$
Sampada
la source
2
Il accepte 99pour Latitude, tant qu'il 99est hors de portée -90, +90et donc invalide.
ako le
14
^-?[0-9]{1,3}(?:\.[0-9]{1,10})?$

Répartition des expressions régulières:

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

-? # accepter les valeurs négatives

^ # Début de chaîne

[0-9]{1,3} # Correspond à 1-3 chiffres (c'est-à-dire de 0 à 999)

(?: # Essayez de faire correspondre ...

\. # un point décimal

[0-9]{1,10} # suivi d'un à 10 chiffres (par exemple 0-9999999999)

)? # ... en option

$ # Fin de chaîne

Zehra Nasif
la source
Je pense que le vôtre est le plus élégant. Premièrement, cela a fonctionné immédiatement sans avoir à modifier et à remplacer les caractères d'échappement. Deuxièmement, il est court. Troisièmement, il est facile à comprendre.
Jim Rota
9

Essaye ça:

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

Découvrez-le sur:

http://regexpal.com/

Collez l'expression dans la case du haut, puis mettez des choses comme ceci dans la case du bas:

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

Répartition des expressions régulières:

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

Maintenant, ce que cela ne fait PAS, c'est se limiter à cette plage:

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

Au lieu de cela, il se limite simplement à cette plage:

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

Mais il s'agit principalement de décomposer chaque morceau de l'expression.

user1439929
la source
7

Voici une version plus stricte:

^([-+]?\d{1,2}[.]\d+),\s*([-+]?\d{1,3}[.]\d+)$
  • Latitude = -90 -+90
  • Longitude = -180-+180
Alix Axel
la source
1
Je crois que {1,2} devrait venir en premier, puis {1,3}
randunel
@Arjan: Corrigé, je confond toujours les deux. Merci!
Alix Axel
5

Python:

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')

Latitude devrait échouer dans l'exemple.

picmate 涅
la source
4

@ macro-ferrari j'ai trouvé un moyen de le raccourcir, et sans regarder vers l'avenir à la lumière de toutes les discussions récentes sur les moteurs regex

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

entrez la description de l'image ici

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

entrez la description de l'image ici

Arun Karunagath
la source
Belle explication, btw comment avez-vous obtenu ce contrôle de flux un logiciel spécifique utilisé. celui-ci regexper.com ?
silentsudo
3

Je crois que vous utilisez \ w (caractère de mot) là où vous devriez utiliser \ s (espace). Les caractères du mot se composent généralement de [A-Za-z0-9_], ce qui exclut votre espace, qui ne correspond alors plus au signe moins facultatif ou à un chiffre.

ourson
la source
3

Cela fonctionnerait pour un format comme celui-ci: 31 ͦ 37.4 'E

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

Rubis

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
la source
0

Une méthode complète et simple de l'objectif C pour vérifier la configuration correcte de la latitude et de la longitude est:

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

searchString est l'entrée que l'utilisateur entrerait dans le champ de texte respectif.

saxenarishav
la source
0

PHP

Voici la version de PHP (les valeurs d'entrée sont: $latitudeet $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
la source
-1

Vous pouvez essayer ceci:

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
la source
-2

Essaye ça:

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

Essaye ça:

(?<!\d)([-+]?(?:[1-8]?\d(?:\.\d+)?|90(?:\.0+)?)),\s*([-+]?(?:180(?:\.0+)?|(?:(?:1[0-7]\d)|(?:[1-9]?\d))(?:\.\d+)?))(?!\d)`
user4325241
la source
5
Les réponses en code pur sont rarement une bonne idée. Veuillez ajouter un texte descriptif à votre réponse.
timclutton
fonctionne très bien: valide avec précision et sélectionne lat, long de tout texte environnant. Cependant, ne limite pas le nombre de chiffres significatifs autorisés après la virgule décimale.
user4325241