Ekspresi reguler untuk mencocokkan koordinat lintang / bujur?

149

Saya mencoba membuat ekspresi reguler untuk mencocokkan koordinat lintang / bujur. Untuk mencocokkan angka presisi ganda yang saya gunakan (\-?\d+(\.\d+)?), dan mencoba menggabungkannya menjadi satu ekspresi:

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

Saya berharap ini cocok dengan ganda, koma, mungkin beberapa ruang, dan dua lagi, tetapi tampaknya tidak berhasil. Khususnya itu hanya berfungsi jika tidak ada ruang, tidak satu atau lebih. Apa yang telah saya lakukan salah?

Jake Petroules
sumber

Jawaban:

117

Spasi adalah \ s, bukan \ w

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

Lihat apakah ini berfungsi

Eric C
sumber
1
Saya harus menggunakan dot alih-alih koma: /^(\-?\d+(\.\d+)?) Di siniAdot. endMod \ s * (\ -? \ d + (\. \ d +)?) $ /
kolodi
Ini menerima nilai di luar rentang yang diizinkan untuk lat dan long. mis., 91.181
Arun Karunagath
Ini berfungsi untuk koordinat x / y dari sistem referensi spasial yang diproyeksikan juga
DeEgge
218

Yang ini akan benar-benar cocok dengan nilai lintang dan bujur yang berada dalam kisaran yang benar:

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

Cocok

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

Tidak cocok

  • -90., -180.
  • +90.1, -100.111
  • -91, 123,456
  • 045, 180
Iain Fraser
sumber
Ini luar biasa. Kudos untuk inklusi jangkauan pemeriksaan.
radj
1
Saya pikir Anda memiliki salah ketik dalam contoh pertandingan pertama Anda. Saya ragu bahwa RegEx akan cocok dengan 3 nilai.
Burkhard
Tetap. Itu dimaksudkan sebagai dua contoh terpisah.
Iain Fraser
7
Dimodifikasi untuk menerima spasi putih di kedua sisi koma: ^ [- +]? ([1-8]? \ D (\. \ D +)? | 90 (\. 0 +)?) \ S *, \ s * [- +]? (180 (\. 0 +)? | ((1 [0-7] \ d) | ([1-9]? \ d)) (\. \ d +)?) $
puddinman13
2
Saya mengubah ini untuk mendapatkan lat lat itu di dalam grup penangkap dengan menggunakan ?:sintaksis grup yang tidak menangkap, serta menangkap polaritas(^[-+]?(?:[1-8]?\d(?:\.\d+)?|90(?:\.0+)?)),\s*([-+]?(?:180(?:\.0+)?|(?:(?:1[0-7]\d)|(?:[1-9]?\d))(?:\.\d+)?))$
narthur157
109

Saya menggunakan yang ini (format desimal, dengan 6 digit desimal):

Garis Lintang

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

Visualisasi ekspresi reguler Latitude

Garis bujur

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

Bujur Visualisasi ekspresi reguler


Berikut adalah intisari yang menguji keduanya, dilaporkan di sini juga, untuk kemudahan akses. Ini adalah tes Java TestNG. Anda perlu Slf4j, Hamcrest dan Lombok untuk menjalankannya:

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
sumber
Ini adalah regex yang sangat bagus! Tetapi apakah mungkin untuk mempersingkat sedikit? :) Jika tidak bisa, tidak apa-apa tapi kode yang lebih pendek selalu diterima :)
Airikr
@ErikEdgren Saya tidak menemukan cara untuk mempersingkat :(
Marco Ferrari
1
Ok: / Oh well. Regex Anda masih luar biasa;)
Airikr
2
nice visual: D Tidak tahu tentang situs web ini! Terima kasih !
Damiii
Apa url situs web
K - Keracunan dalam SO tumbuh.
19

Sebenarnya Alix Axel, regex di atas salah dalam garis lintang, titik pandang garis bujur.

Pengukuran garis lintang berkisar dari –90 ° hingga + 90 ° Pengukuran garis bujur berkisar dari –180 ° hingga + 180 °

Jadi regex yang diberikan di bawah ini memvalidasi lebih akurat.
Juga, sesuai pemikiran saya, tidak ada yang harus membatasi titik desimal dalam lintang / bujur.

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

ATAU untuk Tujuan C

^([-+]?\\d{1,2}([.]\\d+)?),\\s*([-+]?\\d{1,3}([.]\\d+)?)$
Sampada
sumber
2
Itu menerima 99untuk Latitude, sementara 99berada di luar jangkauan -90, +90dan tidak valid.
ako
14
^-?[0-9]{1,3}(?:\.[0-9]{1,10})?$

Regex breakdown:

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

-? # menerima nilai negatif

^ # Mulai string

[0-9]{1,3} # Cocokkan 1-3 digit (yaitu 0-999)

(?: # Cobalah untuk mencocokkan ...

\. # titik desimal

[0-9]{1,10} # diikuti oleh satu hingga 10 digit (yaitu 0-9999999999)

)? # ... secara opsional

$ # Akhir string

Zehra Nasif
sumber
Saya pikir milikmu adalah yang paling elegan. Pertama, itu bekerja segera tanpa harus mengedit dan mengganti karakter melarikan diri. Kedua, pendek. Ketiga, mudah dimengerti.
Jim Rota
9

Coba ini:

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

Lihat di:

http://regexpal.com/

Rekatkan ekspresi di kotak atas, lalu masukkan hal-hal seperti ini di kotak bawah:

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

Regex breakdown:

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

Sekarang, apa yang TIDAK dilakukan adalah membatasi diri pada kisaran ini:

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

Alih-alih, ini sederhana membatasi diri ke rentang ini:

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

Tetapi intinya adalah terutama untuk memecah setiap bagian dari ekspresi.

pengguna1439929
sumber
7

Ini versi yang lebih ketat:

^([-+]?\d{1,2}[.]\d+),\s*([-+]?\d{1,3}[.]\d+)$
  • Latitude = -90-+90
  • Bujur = -180-+180
Alix Axel
sumber
1
Saya percaya bahwa {1,2} harus didahulukan, kemudian {1,3}
randunel
@ Arjan: Memperbaiki, saya selalu membingungkan keduanya. Terima kasih!
Alix Axel
5

Python:

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

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

Latitude seharusnya gagal dalam contoh.

teman satu 涅
sumber
4

@ macro-ferrari Saya memang menemukan cara untuk mempersingkat, dan tanpa melihat ke depan dalam terang semua pembicaraan terakhir tentang mesin regex

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

masukkan deskripsi gambar di sini

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

masukkan deskripsi gambar di sini

Arun Karunagath
sumber
Penjelasan yang bagus, tapi bagaimana Anda bisa mengontrol aliran perangkat lunak tertentu yang Anda gunakan. ini regexper.com ?
silentsudo
3

Saya yakin Anda menggunakan \ w (karakter kata) di mana Anda seharusnya menggunakan \ s (spasi putih). Karakter kata biasanya terdiri dari [A-Za-z0-9_], sehingga mengecualikan ruang Anda, yang kemudian gagal mencocokkan dengan tanda minus opsional atau digit.

theraccoonbear
sumber
3

Ini akan berfungsi untuk format seperti ini: 31 ͦ 37,4 'E

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

Rubi

Garis bujur -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
sumber
0

Metode yang lengkap dan sederhana dalam tujuan C untuk memeriksa pola lintang dan bujur yang benar adalah:

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

di mana searchingString adalah input yang akan dimasukkan pengguna di bidang teks masing-masing.

saxenarishav
sumber
0

PHP

Ini adalah versi PHP (nilai inputnya adalah: $latitudedan $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
sumber
-1

Anda dapat mencoba ini:

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

Coba ini:

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

Coba ini:

(?<!\d)([-+]?(?:[1-8]?\d(?:\.\d+)?|90(?:\.0+)?)),\s*([-+]?(?:180(?:\.0+)?|(?:(?:1[0-7]\d)|(?:[1-9]?\d))(?:\.\d+)?))(?!\d)`
pengguna4325241
sumber
5
Jawaban kode murni jarang merupakan ide yang bagus. Silakan tambahkan beberapa teks deskriptif untuk jawaban Anda.
timclutton
berfungsi dengan baik: memvalidasi secara akurat, dan memilih lat, panjang dari teks di sekitarnya. Namun, tidak membatasi jumlah digit signifikan yang dimungkinkan setelah titik desimal.
user4325241