用正则表达式解析 'min:sec' 字符串
Posted
技术标签:
【中文标题】用正则表达式解析 \'min:sec\' 字符串【英文标题】:Parsing 'min:sec' string with a regex用正则表达式解析 'min:sec' 字符串 【发布时间】:2013-06-13 17:58:43 【问题描述】:我正在尝试解析包含由:
分隔的分钟和秒的字符串。 min 和 secs 都是可选的(不过需要提供一个)。这是我希望从我的正则表达式中得到的:
'0' // => '', '0'
'30' // => '', '30'
':30' // => '', '30'
'1:' // => '1', ''
'1:30' // => '1', '30'
不需要获取空字符串,之后会使用parseInt(value, 10) || 0
解析,所以可以是0
,''
,undefined
,...
我试过这个正则表达式:
^([0-9]+)?:?([0-9]+)?$
但是当只有一个值且没有分隔符时,它被认为是一分钟:
'0' // => '0', '' <= wrong result
'30' // => '30', '' <= wrong result
':30' // => '', '30'
'1:' // => '1', ''
'1:30' // => '1', '30'
你可以看到test case here。
有什么想法吗?
编辑: 我当前的实现(没有正则表达式)如下所示:
var min, parts, sec, bp;
bp = '1:30';
parts = bp.split(':');
if (parts.length === 2)
min = parts[0];
sec = parts[1];
else
min = 0;
sec = parts[0];
【问题讨论】:
你为什么不做一个拆分? 我目前正在使用split
,但我正在尝试使其与正则表达式一起使用。如果我找不到解决方案,我会坚持我目前的实施。
我对您寻找理想解决方案表示赞赏,但我看不出使用正则表达式会如何改进任何事情。它只会让你的代码更难阅读/维护,效率更低。
(':' + '1:30').split(':').slice(-2)
(':' + '30').split(':').slice(-2)
您当前的实现对我来说看起来很完美。为什么要改变它?它简单、易读且有效。将其包装在一个函数中(以供重复使用)并收工!
【参考方案1】:
不要将第二组设为可选,将冒号包裹在非捕获组中并设置该选项并将 + 替换为 * ^(?:([0-9]*):)?([0-9]*)$
【讨论】:
【参考方案2】:检查以下正则表达式:
^(?:(?:(\d+):)?|:)(\d*)$
Scriptular Test here.
var min, match, sec, bp;
bp = '1:30';
match = /^(?:(?:(\d+):)?|:)(\d*)$/.exec(bp);
min = parseInt(match[1], 10) || 0;
sec = parseInt(match[2], 10) || 0;
输出:
0 -> min: 0 sec: 0
30 -> min: 0 sec: 30
:30 -> min: 0 sec: 30
1: -> min: 1 sec: 0
1:30 -> min: 1 sec: 30
javascript Demo here.
【讨论】:
你有一个捕获组。如果你真的想使用前瞻,它应该是一个简单的^([0-9]+(?=:))?:?([0-9]+)?$
@Bergi 实际上是故意的。所以缺失值最终会变成空字符串而不是undefined
。
好的,我明白了。不过,第二次前瞻是多余的,应该简化为^([0-9]+(?=:)|):?([0-9]+)?$
@Bergi 哦,是的,当然。我在进行一些测试时添加了它。因为没多大关系,最后我把它忘在那里了。感谢您的提醒!
@Bergi 看起来不错!实际上我不需要得到一个空字符串,因为我会在之后将它解析为一个 int。我正在做一个parseInt(match[1], 10) || 0
所以得到未定义不是什么大不了的事。【参考方案3】:
在您的正则表达式中,所有内容都是可选的,如果只有一个数字存在,它将与第一组匹配。您需要将以下冒号作为该捕获组的要求(但不是其中的一部分,因此请使用额外的非捕获组):
^(?:([0-9]*):)?([0-9]*)$
var parts = bp.match(/^(?:(\d*):)?(\d*)$/);
if (parts)
var min = +parts[1] || 0, // can be undefined if no colon
sec = +parts[2];
else
throw new SyntaxError("Invalid 'min:sec' format");
顺便说一句,如果您仍然使用parseInt
,那么捕获冒号不会受到伤害。那么最简单(最短)的就是(\d*:)?(\d*)
:
var parts = bp.match(/^(\d*:)?(\d*)$/);
if (parts)
var min = parseInt(parts[1], 10) || 0,
sec = parseInt(parts[2], 10) || 0;
else
throw new SyntaxError("Invalid 'min:sec' format");
【讨论】:
【参考方案4】:这个怎么样:
^([0-9]+:)?([0-9]+)?$
【讨论】:
不错!只有:30
不匹配,我们越来越近了!【参考方案5】:
我希望这对您有所帮助,并且您希望得到一个数组作为结果:
function parseTime(time)
var tranfTime = time.replace(':',',').split(',');
if(time.length > 2 || time[1] === ':')
time = tranfTime;
else
time = [''].concat(tranfTime);
return time;
parseTime('1:30') -> ['1','30']
【讨论】:
为什么不直接在:
上拆分呢?另请注意,较旧的 IE 不支持使用括号表示法访问单个字符,您最好使用 .charAt
感谢您的回答,但我更喜欢我原来的split
代码。【参考方案6】:
以下正则表达式似乎是一个:
^(?:(\d+):)?:?(\d+)?$
见test case。
【讨论】:
...你是对的。其实这没什么大不了的,但我会继续寻找完美的正则表达式。 我以为你需要一个空字符串。如果你不这样做,事情就会容易得多。如果还没有人收到,我会更新我的。 @acdcjunior 抱歉,我编辑的问题不够精确。如果您即使没有空字符串也更新您的,我会接受它:) @TimPetricola:已经有了可行的“完美”解决方案的答案。你没有测试过 user1937198 的(或我的,实际上结果是一样的)吗?您应该投票和/或接受他们。 @Bergi 是的,你是对的,它在 Scriptular 上不起作用,因为我不知道是什么原因,但它在控制台中运行良好......我的错。以上是关于用正则表达式解析 'min:sec' 字符串的主要内容,如果未能解决你的问题,请参考以下文章