【问题标题】:Regular expressions for matching a list of longitude latitude pairs用于匹配经纬度对列表的正则表达式
【发布时间】:2023-03-21 11:07:01
【问题描述】:

我一直在寻找一种方法来验证纬度/经度对列表。虽然我找到了一些关于如何validate pairs 和如何validate a list of pairs 的好例子,但我一直无法编写一个正则表达式来满足我的具体要求。要求如下:

  1. 每个纬度/经度对都必须包含有效值(由first link 解决)
  2. 每对必须用逗号与其他对隔开。 The second link 使用分号,但是用逗号替换它会导致正则表达式出现一些问题
  3. 必须有偶数个坐标,以便每个坐标都配对
  4. 逗号后面的空格是可以的
  5. 至少需要3个坐标对,这样坐标才能形成一个多边形(但我们不必担心重复的坐标),最后的坐标对后面不能跟逗号

以下条目应该是有效的:

32.3078, 64.7505,
27.6648, 81.5158,
18.2208, 66.5901

32.3078, 64.7505,
27.6648, 81.5158,
18.2208, 66.5901,
32.3078, 64.7505,
27.6648, 81.5158,
18.2208, 66.5901

32.3078,64.7505,27.6648,81.5158,18.2208,66.5901

虽然这些应该是无效的:

//only 1 pair
32.3078, 64.7505

//no commas separating each pair
32.3078, 64.7505
27.6648, 81.5158
18.2208, 66.5901

//odd number of pairs
32.3078, 64.7505,
27.6648, 81.5158,
18.2208, 66.5901,
32.3078, 64.7505,
27.6648, 81.5158,
18.2208

//comma after the final pair
32.3078, 64.7505,
27.6648, 81.5158,
18.2208, 66.5901,

【问题讨论】:

  • 首先用逗号或空格分割,然后对照边界测试每个数字。

标签: javascript regex


【解决方案1】:

改进的解决方案

编辑:多亏了建议,我重新设计了我的解决方案,并决定担心尾随逗号和边界检查代码而不是正则表达式是最有意义的。我已经能够显着降低正则表达式的复杂性。

以下是我的最终解决方案:

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

主组匹配单个坐标:

(-?(\d{1,3})(\.\d+)?,\s*)
 -?                        Optional negative sign
   (\d{1,3})               Match any sequence of 1 to 3 digits
            (\.\d+)?       Optionally match a decimal point followed by at least 1 digit
                    ,\s*   Match a comma followed by any amount or type of white-space

这将匹配83.1642,1,987.654321,-91.000,它们在格式上都是有效的(我们想要的),尽管它们可能不在范围内(我们可以稍后在代码中检查)。

现在,对于正则表达式的其余部分:

(-?(\d{1,3})(\.\d+)?,\s*){2}
                         {2} Requires that exactly a pair of points be present

((-?(\d{1,3})(\.\d+)?,\s*){2}){3,}
                              {3,} Requires that 3 or more pairs of points must be present

当然,^$ 分别表示字符串的开始和结束。这给了我们正则表达式来(几乎!)匹配我们问题中的所有字符串:^((-?(\d{1,3})(\.\d+)?,\s*){2}){3,}$

您可能会注意到这需要一个逗号,这与我们的问题不同。以下字符串被认为是有效的:

32.3078, 64.7505,
27.6648, 81.5158,
18.2208, 66.5901,
32.3078, 64.7505,
27.6648, 81.5158,
18.2208, 66.5901,
32.3078, 64.7505,
27.6648, 81.5158,
18.2208, 66.5901,
32.3078,64.7505,27.6648,81.5158,18.2208,66.5901,

要解决尾随逗号问题,我们可以简单地将逗号连接到代码中的字符串,如下所示:

(string + ',').match(/^((-?(\d{1,3})(\.\d+)?,\s*){2}){3,}$/)

瞧!我们的代码现在匹配坐标对列表,没有尾随逗号!


旧解决方案

当我想通时,我正要发布我的问题,所以这是我的解决方案:

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

上半场

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

应该匹配第一行减去第一行末尾的逗号。下半场,

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

匹配以下所有行,至少需要 2 个以上的坐标对,总数至少为 3 个。本来就需要偶数个坐标。

请参阅regex101 以了解工作查询

【讨论】:

  • 我认为您在通过正则表达式进行所有检查时走错了路,特别是检查数字范围并且因为您的模式保持近似值。如果我是你,我将只使用正则表达式检查允许的字符,第二次,我将使用代码按此顺序检查(最终)坐标和值范围的数量。这样做可以避免太长的模式、更易读的代码并避免大量无用的捕获组。
  • 与上述相同的 cmets。很好的问题,但不赞成这个提议的答案,很难读。如果它不是字符串的结尾,您是否可以先重新处理您的输入以在同一行的每个第二个逗号之后插入一个“换行符”?以及关于小于 180 的值验证的相同评论:这不是正则表达式的好工作。
  • 我发现这个正则表达式非常庞大而且非常恶心。它不仅难以阅读,而且您不会为可能需要类似解决方案的其他人解释任何内容。不值得一票。我相信有更好的答案
  • 感谢您的建议,我添加了改进的解决方案。感谢指点!
猜你喜欢
  • 2012-02-11
  • 2011-03-31
  • 2011-07-24
  • 1970-01-01
  • 1970-01-01
  • 2011-03-12
  • 2010-10-10
  • 2018-01-08
  • 1970-01-01
相关资源
最近更新 更多