Wyrażenie regularne do dopasowywania współrzędnych szerokości / długości geograficznej?


149

Próbuję utworzyć wyrażenie regularne do dopasowania współrzędnych szerokości / długości geograficznej. Aby dopasować liczbę o podwójnej precyzji, której użyłem (\-?\d+(\.\d+)?)i próbowałem połączyć ją w jedno wyrażenie:

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

Spodziewałem się, że to pasuje do podwójnego, przecinka, może trochę spacji i innego podwójnego, ale wydaje się, że nie działa. W szczególności działa tylko wtedy, gdy NIE ma miejsca, ani jednego ani więcej. Co zrobiłem źle?

Odpowiedzi:


117

Spacja to \ s, a nie \ w

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

Sprawdź, czy to działa


1
Musiałem użyć kropki zamiast przecinka: /^(\-?\d+(\.\d+)?) Tutaj endMod \ s * (\ -? \ d + (\. \ d +)?) $ /
kolodi

Akceptuje wartości spoza dozwolonego zakresu dla łat i długich. np. 91,181
Arun Karunagath

Działa to również dla współrzędnych x / y rzutowanych systemów odniesień przestrzennych
DeEgge

218

Ten będzie ściśle dopasowany do wartości szerokości i długości geograficznej, które mieszczą się w poprawnym zakresie:

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

mecze

  • +90,0, -127,554334
  • 45, 180
  • -90, -180
  • -90 000, -180,0000
  • +90, +180
  • 47,1231231, 179,999999999

Nie pasuje

  • -90, -180.
  • +90,1, -100,111
  • -91, 123,456
  • 045, 180

To jest niesamowite. Uznanie za włączenie kontroli zakresu.
radj

1
Myślę, że masz literówkę w przykładzie pierwszego dopasowania. Wątpię, czy wyrażenie RegEx będzie pasowało do 3 wartości.
Burkhard

Naprawiony. Miały to być dwa oddzielne przykłady.
Iain Fraser

7
Zmodyfikowano, aby akceptować spacje po obu stronach przecinka: ^ [- +]? ([1-8]? \ D (\. \ D +)? | 90 (\. 0 +)?) \ S *, \ s * [- +]? (180 (\. 0 +)? | ((1 [0-7] \ d) | ([1-9]? \ d)) (\. \ d +)?) $
puddinman13

2
Zmieniłem to, aby uzyskać tylko ten lat lon w grupach przechwytywania, używając ?:składni grupy nie przechwytującej, a także polaryzacji przechwytywania(^[-+]?(?:[1-8]?\d(?:\.\d+)?|90(?:\.0+)?)),\s*([-+]?(?:180(?:\.0+)?|(?:(?:1[0-7]\d)|(?:[1-9]?\d))(?:\.\d+)?))$
narthur157

109

Używam tych (format dziesiętny, z 6 cyframi dziesiętnymi):

Szerokość

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

Wizualizacja wyrażeń regularnych w Latitude

Długość geograficzna

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

Długość geograficzna Wizualizacja wyrażenia regularnego


Oto streszczenie, które testuje oba, opisane tutaj, pod kątem łatwości dostępu. To test Java TestNG. Potrzebujesz Slf4j, Hamcrest i Lombok, aby go uruchomić:

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

To był naprawdę fajny regex! Ale czy można go trochę skrócić? :) Jeśli nie, to w porządku, ale skrócenie kodu jest zawsze mile widziane :)
Airikr

@ErikEdgren Nie znalazłem sposobu, żeby to skrócić :(
Marco Ferrari

1
Ok: / No cóż. Twoje wyrażenie regularne jest nadal świetne;)
Airikr

2
ładny obraz: D Nie wiedziałem o tej stronie! Dziękuję Ci !
Damiii,

Jaki jest adres URL witryny
K - Toksyczność w SO rośnie.

19

Właściwie Alix Axel, powyższe wyrażenie regularne jest błędne w zakresie szerokości i długości geograficznej.

Zakres pomiarów szerokości geograficznej wynosi od –90 ° do + 90 ° Pomiary długości geograficznej wahają się od –180 ° do + 180 °

Zatem wyrażenie regularne podane poniżej sprawdza się dokładniej.
Ponadto, zgodnie z moją myślą, nikt nie powinien ograniczać miejsca dziesiętnego w szerokości / długości geograficznej.

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

LUB dla celu C

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

2
Akceptuje 99za Latitude, podczas gdy 99jest poza zakresem, -90, +90a więc nieważne.
ako

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

Podział Regex:

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

-? # akceptuje wartości ujemne

^ # Początek ciągu

[0-9]{1,3} # Dopasuj 1-3 cyfry (np. 0-999)

(?: # Spróbuj dopasować ...

\. # przecinek dziesiętny

[0-9]{1,10} #, po którym następuje od jednej do 10 cyfr (np. 0-9999999999)

)? # ...opcjonalnie

$ # Koniec ciągu


Myślę, że twój jest najbardziej elegancki. Po pierwsze, działało natychmiast, bez konieczności edytowania i zastępowania znaków ucieczki. Po drugie, jest krótkie. Po trzecie, łatwo to zrozumieć.
Jim Rota,

9

Spróbuj tego:

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

Sprawdź to na:

http://regexpal.com/

Wklej wyrażenie w górnym polu, a następnie umieść takie rzeczy w dolnym polu:

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

Podział 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).

To, czego to NIE robi, to ograniczenie się do tego zakresu:

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

Zamiast tego po prostu ogranicza się do tego zakresu:

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

Ale chodzi głównie o rozbicie każdego fragmentu wyrażenia.


7

Oto bardziej rygorystyczna wersja:

^([-+]?\d{1,2}[.]\d+),\s*([-+]?\d{1,3}[.]\d+)$
  • Szerokość geograficzna = -90-+90
  • Długość geograficzna = -180-+180

1
Uważam, że najpierw powinno być {1,2}, a następnie {1,3}
randunel

@Arjan: Naprawiono, zawsze mylę te dwie rzeczy. Dzięki!
Alix Axel

5

Pyton:

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

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

W tym przykładzie usługa Latitude powinna zawieść.


4

@ macro-ferrari Znalazłem sposób, aby to skrócić i bez patrzenia w przyszłość w świetle wszystkich ostatnich rozmów o silnikach regex

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

wprowadź opis obrazu tutaj

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

wprowadź opis obrazu tutaj


Niezłe wyjaśnienie, przy okazji, w jaki sposób uzyskałeś tę kontrolę przepływu w jakimkolwiek używanym oprogramowaniu. ten regexper.com ?
silentsudo

3

Uważam, że używasz \ w (znak słowa), w którym powinieneś używać \ s (spacji). Znaki słów zazwyczaj składają się z [A-Za-z0-9_], więc wyklucza to twoją spację, która następnie nie pasuje do opcjonalnego znaku minus lub cyfry.


3

To zadziała dla formatu takiego: 31 ͦ 37,4 'E

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

1

Rubin

Długość geograficzna -179.99999999..180

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

Szerokość geograficzna -89,999999999..90

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

0

Kompletna i prosta metoda sprawdzania poprawności wzoru szerokości i długości geograficznej w celu C to:

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

gdzie ciąg szukany jest danymi wejściowymi, które użytkownik wprowadziłby w odpowiednim polu tekstowym.


0

PHP

Oto wersja PHP (wartości wejściowe to: $latitudei $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.
}

-1

Możesz spróbować tego:

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})?$/;

-2

Spróbuj tego:

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

-2

Spróbuj tego:

(?<!\d)([-+]?(?:[1-8]?\d(?:\.\d+)?|90(?:\.0+)?)),\s*([-+]?(?:180(?:\.0+)?|(?:(?:1[0-7]\d)|(?:[1-9]?\d))(?:\.\d+)?))(?!\d)`

5
Odpowiedzi w postaci czystego kodu rzadko są dobrym pomysłem. Dodaj opisowy tekst do swojej odpowiedzi.
timclutton

działa świetnie: sprawdza dokładnie i wybiera szerokość, długość z dowolnego otaczającego tekstu. Nie ogranicza jednak liczby cyfr znaczących, które dopuszcza po przecinku.
user4325241
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.