匹配部分的可选部分

问题描述:

我有一个正则表达式设置为匹配US格式的日期和时间。它看起来像这样:匹配部分的可选部分

/(\d{1,2})\/(\d{1,2})\/(\d{2,4}) (\d{1,2}):(\d{1,2})(am|pm|AM|PM|Am|Pm)/ 

但是,我需要它也匹配日期,不包含时间组件。

如何修改这一点,因此,如果它是一个日期,我得到的3场比赛,如果它是一个日期 - 时间,我送六?

Group的时间,并使其optional

/(\d{1,2})\/(\d{1,2})\/(\d{2,4})(?: (\d{1,2}):(\d{1,2})(am|pm|AM|PM|Am|Pm))?/ 

?:抑制拍摄,让你不附加组结束了,如果时间存在。

另外,如果你不是太挑剔允许aMpM,你可以用相当不区分大小写的修改简化:

/(\d{1,2})\/(\d{1,2})\/(\d{2,4})(?: (\d{1,2}):(\d{1,2})([ap]m))?/i 

事实上,使用?你甚至可以缩短图形另外, (因为\d?短于{1,2}

/(\d\d?)\/(\d\d?)\/(\d{2,4})(?: (\d\d?):(\d\d?)([ap]m))?/i 

不过请注意,在任何情况下,你仍然会得到6组(7如果算上整个匹配) - 这是菊ST,最后三会undefined

> groups = '11/11/11'.match(/(\d{1,2})\/(\d{1,2})\/(\d{2,4})(?: (\d{1,2}):(\d{1,2})([ap]m))?/i) 
["11/11/11", "11", "11", "11", undefined, undefined, undefined] 

同样使用exec代替时发生。但这些都是容易的,如果需要过滤掉:

> groups.filter(function(capture) { 
     return typeof capture !== 'undefined'; 
    }); 
["11/11/11", "11", "11", "11"] 

或在此情况下(因为你永远不能拥有空字符串作为捕获):

> groups.filter(function(capture) { 
     return capture; 
    }); 
["11/11/11", "11", "11", "11"] 

使用?时间正则表达式,包装与(?:)非捕获组。

/(\d{1,2})\/(\d{1,2})\/(\d{2,4})(?:\s+(\d{1,2}):(\d{1,2})(am|pm|AM|PM|Am|Pm))?/ 

请注意,文字空间已被替换为\s+

+ - 匹配1个或多个

* - 匹配0个或更多

? - 匹配0或1

+0

虽然没有更好的解决方案,请注意,这不会产生只有4个元素的数组。 –

+0

4个要素?对不起,没有得到你。那问题在哪里? – jkshah

+0

OP希望“只有3个匹配”,所以我认为值得指出的是,在'match'或'exec'中使用模式时,您获得的数组仍然具有相同数量的元素。只是它们中的一些将会是'未定义的'。 –

您可以使用此:

/(\d{1,2})\/(\d{1,2})\/(\d{2,4})(?: (\d{1,2}):(\d{1,2})(am|pm|AM|PM|Am|Pm))?/ 

甚至缩短您的正则表达式:

/(\d{1,2})\/(\d{1,2})\/(\d{2,4})(?: (\d{1,2}):(\d{1,2})([ap]m))?/i 

我包裹的空间和时间成非捕获组,把一个用于? 0或1次发生,使时间可选的。

的字符类[ap]比赛无论是ap以来都ampm结束与m,你可以简单地使用[ap]m和不区分大小写的修改,使[ap]m匹配大写和小写字符。

+1

虽然没有更好的解决方案,但请注意,这不会产生只有4个元素的阵列。此外,你放弃捕获am/pm'位。 –

+0

在缩短xD期间一定发生过谢谢! – Jerry