用正则表达式解析 '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' 字符串的主要内容,如果未能解决你的问题,请参考以下文章

pig - 用正则表达式解析字符串

正则表达式用逗号和等号解析字符串

java的正则表达式解析

需要正则表达式用单引号或双引号解析关键字='值'

easyui界面正则表达式不解析怎么办?

正则表达式解析行首