2017-08-07 113 views
0

在JavaScript中,我正在寻找一个正则表达式来捕获字符串中的多个可选组。但至少有一个组应该存在。正则表达式:使用单个匹配捕获多个可选组

字符串:foo bar 12 seconds 3minutes 4h

正则表达式到目前为止:/(?:(\d+)\s?s(?:econds?)?)?(?:(\d+)\s?m(?:inutes?)?)?(?:(\d+)\s?h(?:ours?)?)?/gi

我需要捕捉12 seconds3minutes4h,只返回在各自小组的数值。

这些时间单位可以存在或交换。我的最终结果将需要看起来像这样:

12s 3m //['12', '3', undefined] 
10 seconds //['10', undefined, undefined] 
4hours //[undefined, undefined, '4'] 
3 minutes //[undefined, '3', undefined] 
1hour 54seconds 7minutes //['54', '7', '1'] 

undefinednull甚至一个空字符串。只要他们在各自的指数。

任何简单的方法来处理这与一个execmatch而不使用循环?

+0

不,没有这样的方式,最干净的将运行3个单独的正则表达式,并以您想要的方式安排匹配。 –

+0

同意@WiktorStribiżew。 12和秒之间的空间有效?我问,因为秒,分钟和小时的格式看起来不同(空格) – JBone

+0

@JBone是的,它是有效的。这些字符串由用户编写。有些使用空间,有些则不使用。所以正则表达式说明了这一点。 – Marian

回答

1

由于Wiktor正确指出,没有办法用一个正则表达式来做到这一点。这里是一个实现一个3-正则表达式溶液的简单函数:

function get_time_parts(text) { 
    var s, m, h; 
    // Seconds part: Either "s", "sec", "secs" "second" or "seconds". 
    s = text.match(/\b(\d+)\s*s(?:ec(?:ond)?s?)?\b/i); 
    s = s ? s[1] : undefined; 
    // Minutes part: Either "m", "min", "mins" "minute" or "minutes". 
    m = text.match(/\b(\d+)\s*m(?:in(?:ute)?s?)?\b/i); 
    m = m ? m[1] : undefined; 
    // Hours part: Either "h", "hr", "hrs" "hour" or "hours". 
    h = text.match(/\b(\d+)\s*h(?:rs?|ours?)?\b/i); 
    h = h ? h[1] : undefined; 
    return (s || m || h) ? [s, m, h] : null; 
} 

正如在注释中规定,该功能允许以下部分时间的变化:

秒部分:或者“S”,“秒” ,“秒”,“秒”或“秒”。
分钟部分:“m”,“min”,“mins”,“分钟”或“分钟”。
小时部分:“h”,“hr”,“hrs”“小时”或“小时”。

正则表达式不区分大小写,因此会允许变化,例如, HR,Sec,mIN等如果没有任何部分存在,则该函数返回null。

-1

不知道这与您匹配的各种类型的输入字符串,但这里是我想出了你输入字符串的东西。我假设秒数先到达,然后是分钟,然后是小时,因为您已在问题输入字符串中找到它。此订单是否始终正确?

let str = "foo bar 12 seconds 3minutes 4h"; 
let result = str.match(/(\d+) ?(?:sec|seconds) ?(\d+) ?(?:min|minutes) ?(\d+) ?(?:h|hours?)/); 
console.log(`${result[3]}hour ${result[1]}second ${result[2]}minutes`); 
+0

此解决方案不能用作@Marian发布的正则表达式 - 如果删除其中一个时间单位,则您的正则表达式将不起作用。例如,字符串'foo bar 12a secondds 5m 4h'将强制执行错误。 – archos

1

有没有简单的解决方案,用普通的正则表达式做到这一点。最简单的解决方案是使用exec方法并将值设置为散列(对象)。此外,你可以简化你的正则表达式 - 所有工程,第二,我们的是完全无用的正则表达式。如果你只想要s你应该使用(?:s|second),因为在你的例子中5样品也会匹配。

您的问题,最简单的解决方案(不处理单元的顺序):

var str = "foo bar 12 seconds 5m 4hours"; 
 
var re = /(\d+)\s*([smh])/gi 
 
var hash = {}; 
 

 
var m; 
 
while ((m = re.exec(str)) !== null) { 
 
    // get values 
 
    var value = m[1]; 
 
    var unit = m[2].toLowerCase(); 
 

 
    // set value 
 
    hash[unit] = value; 
 
} 
 

 
console.log(hash);

该解决方案将始终使用最后一个出现,也不会依赖的顺序上单位。

+0

是的,这将简化我的正则表达式,因为它以_s_开始,所以(':?秒|?)?或'(?:s | second)'仍然会匹配_5个samples_。 但无论如何,这有助于。谢谢。 – Marian