在JavaScript中,我正在寻找一个正则表达式来捕获字符串中的多个可选组。但至少应该有一个小组存在。
字符串:foo bar 12 seconds 3minutes 4h
到目前为止的正则表达式:/(?:(\d+)\s?s(?:econds?)?)?(?:(\d+)\s?m(?:inutes?)?)?(?:(\d+)\s?h(?:ours?)?)?/gi
我需要捕获12 seconds
3minutes
和4h
,只返回各自组中的数字值。
这些时间单位既可以存在,也可以互换。我的最终结果需要看起来像这样:
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']
undefined
null
甚至是一个空字符串。只要它们在各自的索引中。
使用单个exec
或match
而不使用循环来处理此问题的简单方法是什么?
答案 0 :(得分:1)
使用普通正则表达式没有简单的解决方案。最简单的解决方案是使用exec
方法并将值设置为hash(object)。此外,您可以简化正则表达式 - 所有 inute , econd ,我们的在您的正则表达式中完全没用。如果您只想要 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);
此解决方案将始终使用最后一次出现,并且不依赖于单位的顺序。
答案 1 :(得分:1)
正如Wiktor正确指出的那样,单一正则表达式无法做到这一点。这是一个实现3-regex解决方案的简单函数:
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”,“sec”,“secs”,“second”或“seconds”。
分钟部分:“m”,“min”,“min”,“minute”或“minutes”
小时部分:“h”,“hr”,“hrs”,“小时”或“小时”。
正则表达式不区分大小写,因此允许变化,例如HR,Sec,mIN等。如果没有任何部件存在,则该函数返回null。
答案 2 :(得分:-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`);