使用[lon,lat]格式的多个十进制坐标的PCRE正则表达式

时间:2014-09-14 21:38:09

标签: regex coordinates regex-lookarounds regex-greedy

我正在尝试为[lon,lat]坐标创建一个正则表达式。

代码首先检查输入是否以'['开头。 如果是这样,我们通过正则表达式检查坐标的有效性

/([\[][-+]?(180(\.0{1,15})?|((1[0-7]\d)|([1-9]?\d))(\.\d{1,15})?),[-+]?([1-8]?\d(\.\d{1,15})?|90(\.0{1,15})?)[\]][\;]?)+/gm

[lon,lat]的正则表达式测试,小数点后15位[+ - 180度,+ -90度]

它应匹配:

  1. 单坐标:
    • [120,80];
    • [120,80]
  2. 多个坐标
    • [180,90]; [180,67];
    • [180,90]; [180,67]
  3. 有换行符
    • [123,34]; [ - 32,21];
      [12,-67]
  4. 不应该匹配:

    1. 分号分隔符缺失 - 单个
      • [25,67] [76,23];
    2. 分号分隔符丢失 - 多个
      • [25,67]
        [76,23] [12,90];
    3. 我目前有问题;坐标之间(见4& 5)

      jsfiddle equivalent here : http://regex101.com/r/vQ4fE0/4

4 个答案:

答案 0 :(得分:0)

您可以尝试使用此(人类可读)模式:

$pattern = <<<'EOD'
~
(?(DEFINE)
    (?<lon> [+-]?
        (?:
            180 (?:\.0{1,15})?
          |
            (?: 1(?:[0-7][0-9]?)? | [2-9][0-9]? | 0 )
            (?:\.[0-9]{1,15})?
        )
    )
    (?<lat> [+-]?
        (?:
            90 (?:\.0{1,15})? 
          |
            (?: [1-8][0-9]? | 9)
            (?:\.[0-9]{1,15})?
        )
    )
)

\A
\[ \g<lon> , \g<lat> ] (?: ; \n? \[ \g<lon> , \g<lat> ] )* ;?
\z
~x
EOD;

<强>解释

当你必须处理一个长图案时,你必须重复几次相同的子图案,你可以使用几个功能使它更具可读性。

最为人所知的是使用自由间距模式(x修饰符)允许缩进你想要的模式(所有空格都被忽略)和最终要添加评论。

第二个包括在定义部分(?(DEFINE)...)中定义子模式,您可以在其中定义稍后将在主模式中使用的命名子模式。

由于我不想重复描述经度数和纬度数的大型子模式,我在定义部分创建了两个名为pattern“lon”和“lat”的模式。要在主模式中使用它们,我只需要编写\g<lon>\g<lat>

javascript版

var lon_sp = '(?:[+-]?(?:180(?:\\.0{1,15})?|(?:1(?:[0-7][0-9]?)?|[2-9][0-9]?|0)(?:\\.[0-9]{1,15})?))';
var lat_sp = '(?:[+-]?(?:90(?:\\.0{1,15})?|(?:[1-8][0-9]?|9)(?:\\.[0-9]{1,15})?))';
var coo_sp = '\\[' + lon_sp + ',' + lat_sp + '\\]';
var regex = new RegExp('^' + coo_sp + '(?:;\\n?' + coo_sp + ')*;?$');
var coordinates = new Array('[120,80];',
                            '[120,80]',
                            '[180,90];[180,67];',
                            '[123,34];[-32,21];\n[12,-67]',
                            '[25,67][76,23];',
                            '[25,67]\n[76,23]');

for (var i = 0; i<coordinates.length; i++) {
    console.log("\ntest "+(i+1)+": " + regex.test(coordinates[i]));
}

fiddle

答案 1 :(得分:0)

试试这个:

^(\[([+-]?(?!(180\.|18[1-9]|19\d{1}))\d{1,3}(\.\d{1,15})?,[+-]?(?!(90\.|9[1-9]))\d{1,2}(\.\d{1,15})?(\];$|\]$|\];\[)){1,})

演示:http://regex101.com/r/vQ4fE0/7

<强>解释

  • ^(\[

必须以括号

开头
  • [+-]?

在数字前面可能包含+ - 也可能不包含+ -

  • (?!(180\.|18[1-9]|19\d{1}))

不应包含180.181-18919x

  • \d{1,3}(\.\d{1,15})?

否则,任何包含1或3位数字的数字,包括或不包含小数(最多15位)

  • (?!(90\.|9[1-9]))

90检查与此类似,我们不允许90.91-99

  • \d{1,2}(\.\d{1,15})?

否则,任何包含1或2位数字的数字,包括或不包含小数(最多15位)

  • (\];$|\]$|\];\[)

括号体的结尾必须有一个;分隔两个括号体,否则它必须是该行的末尾。

  • {1,}

括号可以存在1次或多次


希望这有用。

答案 2 :(得分:0)

这可能有用。请注意,您有很多捕获组,其中没有一个 由于递归量词,会给你很好的信息。

 # /^(\[[-+]?(180(\.0{1,15})?|((1[0-7]\d)|([1-9]?\d))(\.\d{1,15})?),[-+]?([1-8]?\d(\.\d{1,15})?|90(\.0{1,15})?)\](?:;\n?|$))+$/

 ^ 
 (                               # (1 start)
      \[
      [-+]? 
      (                               # (2 start)
           180
           ( \. 0{1,15} )?                 # (3)
        |  
           (                               # (4 start)
                ( 1 [0-7] \d )                  # (5)
             |  
                ( [1-9]? \d )                   # (6)
           )                               # (4 end)
           ( \. \d{1,15} )?                # (7)
      )                               # (2 end)
      ,
      [-+]? 
      (                               # (8 start)
           [1-8]? \d 
           ( \. \d{1,15} )?                # (9)
        |  
           90
           ( \. 0{1,15} )?                 # (10)
      )                               # (8 end)
      \]
      (?: ; \n? | $ )
 )+                              # (1 end)
 $

答案 3 :(得分:0)

尝试一种函数方法,其中函数可以为您执行某些拆分,以及将数字比较委托给正则表达式。我在这里测试了它:http://repl.it/YyG/3

//represents regex necessary to capture one coordinate, which
//  looks like 123 or 123.13532
//  the decimal part is a non-capture group ?:
var oneCoord = '(-?\\d+(?:\\.\\d+)?)';
//console.log("oneCoord is: "+oneCoord+"\n");

//one coordinate pair is represented by [x,x] 
//  check start/end with ^, $
var coordPair = '^\\['+oneCoord+','+oneCoord+'\\]$';
//console.log("coordPair is: "+coordPair+"\n");

//the full regex string consists of one or more coordinate pairs,
//  but we'll do the splitting in the function
var myRegex = new RegExp(coordPair);
//console.log("my regex is: "+myRegex+"\n");

function isPlusMinus180(x)
{
    return -180.0<=x && x<=180.0;
}

function isPlusMinus90(y)
{
    return -90.0<=y && y<=90.0;
}

function isValid(s)
{    
    //if there's a trailing semicolon, remove it
    if(s.slice(-1)==';')
    {
        s = s.slice(0,-1);
    }

    //remove all newlines and split by semicolon
    var all = s.replace(/\n/g,'').split(';');
    //console.log(all);
    for(var k=0; k<all.length; ++k)
    {        
        var match = myRegex.exec(all[k]);
        if(match===null)
            return false;

        console.log("  match[1]: "+match[1]);
        console.log("  match[2]: "+match[2]);

        //break out if one pair is bad
        if(! (isPlusMinus180(match[1]) && isPlusMinus90(match[2])) )
        {
            console.log("  one of matches out of bounds");
            return false;
        }

    }
    return true;
}

var coords = new Array('[120,80];',
    '[120.33,80]',
    '[180,90];[180,67];',
    '[123,34];[-32,21];\n[12,-67]',
    '[25,67][76,23];',
    '[25,67]\n[76,23]',
    '[190,33.33]',
    '[180.33,33]',
    '[179.87,90]',
    '[179.87,91]');


var s;
for (var i = 0; i<coords.length; i++) {
    s = coords[i];
    console.log((i+1)+". ==== testing "+s+" ====");
    console.log("  isValid? => " + isValid(s));
}