【问题标题】:Regular expression for matching latitude/longitude coordinates?匹配纬度/经度坐标的正则表达式?
【发布时间】:2011-03-31 21:59:38
【问题描述】:

我正在尝试创建一个正则表达式来匹配纬度/经度坐标。为了匹配双精度数,我使用了(\-?\d+(\.\d+)?),并尝试将其组合成一个表达式:

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

我希望这可以匹配一个双精度数、一个逗号、也许一些空格和另一个双精度数,但它似乎不起作用。具体来说,它只有在没有空间的情况下才有效,而不是一个或多个。我做错了什么?

【问题讨论】:

    标签: regex


    【解决方案1】:

    这个将严格匹配正确范围内的纬度和经度值:

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

    匹配

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

    不匹配

    • -90., -180.
    • +90.1, -100.111
    • -91, 123.456
    • 045, 180

    【讨论】:

    • 这太棒了。范围检查包含的荣誉。
    • 我认为您的第一个匹配示例中有错字。我怀疑 RegEx 是否会匹配 3 个值。
    • 已修复。它本来是两个独立的例子。
    • 修改为接受逗号两边的空格:^[-+]?([1-8]?\d(\.\d+)?|90(\.0+ )?)\s*,\s*[-+]?(180(\.0+)?|((1[0-7]\d)|([1-9]?\d))(\ .\d+)?)$
    • 我通过使用 ?: 非捕获组语法以及捕获极性 (^[-+]?(?:[1-8]?\d(?:\.\d+)?|90(?:\.0+)?)),\s*([-+]?(?:180(?:\.0+)?|(?:(?:1[0-7]\d)|(?:[1-9]?\d))(?:\.\d+)?))$
    【解决方案2】:

    我正在使用这些(十进制格式,带 6 个十进制数字):

    纬度

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

    经度

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


    Here 是一个测试两者的要点,也在这里报告,以便于访问。这是一个 Java TestNG 测试。你需要 Slf4j、Hamcrest 和 Lombok 来运行它:

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

    【讨论】:

    • 这是一个非常好的正则表达式!但是有没有可能缩短一点呢? :) 如果不能,没关系,但总是欢迎缩短代码 :)
    • @ErikEdgren 我没有找到缩短它的方法:(
    • 好的:/哦,好吧。你的正则表达式仍然很棒;)
    • 漂亮的视觉效果 :D 不知道这个网站!谢谢!
    • 网站网址是什么
    【解决方案3】:

    空格是\s,而不是\w

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

    看看这是否有效

    【讨论】:

    • 我不得不使用点而不是逗号: /^(\-?\d+(\.\d+)?) hereAdot 。 endMod \s*(\-?\d+(\.\d+)?)$/
    • 它接受超出经纬度允许范围的值。例如,91,181
    • 这也适用于投影空间参考系统的 x/y 坐标
    【解决方案4】:

    实际上,Alix Axel,上面的正则表达式在纬度、经度范围的角度是错误的。

    纬度测量范围从 –90° 到 +90° 经度测量范围从 –180° 到 +180°

    所以下面给出的正则表达式验证更准确。
    另外,根据我的想法,没有人应该限制纬度/经度的小数点。

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

    目标 C 的 OR

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

    【讨论】:

    • 它接受99Latitude,而99 超出-90, +90 的范围,因此无效。
    【解决方案5】:
    ^-?[0-9]{1,3}(?:\.[0-9]{1,10})?$
    

    正则表达式分解:

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

    -? # 接受负值

    ^ # 字符串开始

    [0-9]{1,3} # 匹配 1-3 位数字(即 0-999)

    (?: # 尝试匹配...

    \.# 一个小数点

    [0-9]{1,10} # 后跟 1 到 10 位数字(即 0-9999999999)

    )? # ...可选

    $ # 字符串结束

    【讨论】:

    • 我认为你的最优雅。首先,它无需编辑和替换转义字符即可立即工作。其次,它很短。第三,通俗易懂。
    【解决方案6】:

    试试这个:

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

    查看:

    http://regexpal.com/

    将表达式粘贴到顶部框中,然后将类似这样的内容放入底部框中:

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

    正则表达式分解:

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

    现在,它不做的是将自己限制在这个范围内:

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

    相反,它只是将自己限制在这个范围内:

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

    但重点主要是分解每个表达式。

    【讨论】:

      【解决方案7】:

      @macro-ferrari我确实找到了一种缩短它的方法,并且根据最近关于regex engines的所有讨论,我没有向前看

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

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

      【讨论】:

      • 很好的解释,顺便说一句,你是如何获得这个流控制的,你使用的任何特定软件。这个regexper.com?
      【解决方案8】:

      这是一个更严格的版本:

      ^([-+]?\d{1,2}[.]\d+),\s*([-+]?\d{1,3}[.]\d+)$
      
      • 纬度 = -90 -- +90
      • 经度 = -180 -- +180

      【讨论】:

      • 我认为应该先出现 {1,2},然后是 {1,3}
      • @Arjan:固定,我总是混淆这两者。谢谢!
      【解决方案9】:

      Python:

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

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

      示例中的纬度应该失败。

      【讨论】:

        【解决方案10】:

        正则表达式通过将 [0-9] 的多次使用替换为 [0-9] 的子集来缩短 @marco-ferrari 解决方案。还从各个地方删除了不必要的量词,例如 ?:

        lat  "^([+-])?(?:90(?:\\.0{1,6})?|((?:|[1-8])[0-9])(?:\\.[0-9]{1,6})?)$";
        long "^([+-])?(?:180(?:\\.0{1,6})?|((?:|[1-9]|1[0-7])[0-9])(?:\\.[0-9]{1,6})?)$";
        
        
        **Matches for Lat**
        
        Valid between -90 to +90 with up to 6 decimals.
        
        **Matches for Long**
        
        Valid between -180 to +180 with up to 6 decimals.
        

        【讨论】:

          【解决方案11】:

          我相信您使用的是 \w(单词字符),而您应该使用的是 \s(空格)。单词字符通常由 [A-Za-z0-9_] 组成,因此排除了您的空格,然后进一步无法匹配可选的减号或数字。

          【讨论】:

            【解决方案12】:

            这适用于如下格式:31 ͦ 37.4' E

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

            【讨论】:

              【解决方案13】:

              红宝石

              经度-179.99999999..180

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

              纬度-89.99999999..90

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

              【讨论】:

                【解决方案14】:

                Objective C 中用于检查经纬度正确模式的完整而简单的方法是:

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

                其中 searchedString 是用户将在相应文本字段中输入的输入。

                【讨论】:

                  【解决方案15】:

                  PHP

                  这是 PHP 的版本(输入值为:$latitude$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.
                  }
                  

                  【讨论】:

                    【解决方案16】:

                    这个在逗号后强制使用 3 个数字以避免错误匹配:

                    (?&lt;latitude&gt;-?\d+\.\d{3,10}),(?&lt;longitude&gt;-?\d+\.\d{3,10})

                    【讨论】:

                      【解决方案17】:

                      你可以试试这个:

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

                      【讨论】:

                        【解决方案18】:

                        试试这个:

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

                        【讨论】:

                          【解决方案19】:

                          试试这个:

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

                          【讨论】:

                          • 纯代码答案很少是一个好主意。请在您的答案中添加一些描述性文字。
                          • 效果很好:准确地验证,并从任何周围的文本中挑选出经度、经度。但是,它不限制小数点后允许的有效位数。
                          猜你喜欢
                          • 2012-02-11
                          • 2011-07-24
                          • 2023-03-21
                          • 1970-01-01
                          • 2018-02-27
                          • 1970-01-01
                          • 1970-01-01
                          • 1970-01-01
                          • 1970-01-01
                          相关资源
                          最近更新 更多