单个正则表达式匹配范围(1999-2010)或仅一个值(2010)?

时间:2012-06-23 09:31:16

标签: javascript regex

总的来说,我认为我没有遇到过这个问题的通用解决方案。如何匹配可以是范围的字符串,或者只是一个值?

说我想匹配[复杂]日期:

  • 1999 - 2010
  • 公元前323年 - 公元100年
  • 323 BC
  • 1995年至1999年
  • 323 - 322 BC

可以解析这两种情况的一般正则表达式“模板”是什么:

  1. 开始/结束日期(如果存在)
  2. 否则,只需一个日期
  3. 要匹配“1999 - 2010”,您可以这样做

    /(\d+\s*)-(\s*\d+)/ // where $1 and $2 are start and end
    

    为了匹配更复杂的“323 BCE - 100 CE”,你可以做到

    /(\w+\s*\w+)\s*-\s*(\w+\s*\w+)/
    

    为了匹配更简单的“323 BC”,你可以做到

    /\w+\s*\w+/
    

    但是如何编写一个首先检查范围(323 BCE-100 CE)的表达式,如果不存在,则检查单个值(323 BC),还可以处理上面列表中的其他示例吗?

3 个答案:

答案 0 :(得分:2)

通过使比赛的后半部分可选。

/(\w+\s*\w+)(?:\s*-\s*(\w+\s*\w+))?/

示例(JavaScript)

"1900 - 2000".match(/(\w+\s*\w+)(?:\s*-\s*(\w+\s*\w+))?/);
//["1900 - 2000", "1900", "2000"]

"1900 BC".match(/(\w+\s*\w+)(?:\s*-\s*(\w+\s*\w+))?/);
//["1900 BC", "1900 BC", undefined]

请注意,外部可选部分是不匹配的,因此结果数组仅包含您感兴趣的子匹配。

以效率方式收紧模式也是一个想法,例如:寻找数字而不是任何字母数字,并且只允许单个空格(如果这是可接受的)而不是零或更多。

答案 1 :(得分:0)

只是投入另一种可能按你想要的方式运作的模式;

((\d+)( [A-Za-z]+|))((-| - )\d+( [A-Za-z]+|)|)

与Utkanos的模式一样,这可能需要收紧一些而不是匹配任何其他内容。

答案 2 :(得分:0)

你可能正在寻找这样的东西:

var pattern = /(\d+)(\s*(\w+))?(\s*-\s*(\d+)(\s*(\w+))?)?/;
var strings = [
    '1999 - 2010',
    '323 BCE - 100 CE',
    '323 BC',
    '1995-99',
    '323 - 322 BC'
];

for (var i=0, s; s = strings[i]; i++) {
    var m  = s.match(pattern);
    console.log(
        m[1], // beginning year
        m[3], // beginning b/c/e
        m[5], // end year
        m[7]  // end b/c/e
    );
}

输出

1999  undefined  2010       undefined
323   BCE        100        CE
323   BC         undefined  undefined
1995  undefined  99         undefined
323   undefined  322        BC

这里的诀窍是要了解(group)?使(group)成为可选项。与此类似,(foo)+(foo){3}可用于使群组匹配至少一次或恰好三次。

默认情况下,组(foo)是捕获组。这意味着它们的结果将包含在String#match()返回的数组中。您可以将组标记为非捕获,如下所示:(?:wont-be-captured)。有了这个,我们可以进一步修改上述模式:

var pattern = /(\d+)(?:\s*(\w+))?(?:\s*-\s*(\d+)(?:\s*(\w+))?)?/;
for (var i=0, s; s = strings[i]; i++) {
    var m  = s.match(pattern);
    console.log(m[1], m[2], m[3], m[4]);
}