输入的3个示例:
"13-4h50m2s"
"13-4h2s"
"13-50m"
首选代码:
const [hours = 0, minutes = 0, seconds = 0] = input.match(some_regexp)
对于以下3个示例,需要输出{小时、分钟、秒}:
{hours: 4, minutes: 50, seconds: 2}
{hours: 4, minutes: 0, seconds: 2}
{hours: 0, minutes: 50, seconds: 0}
Regex我试过了:/(d+)?[a-z](d+)?[a-z]?(d+)?[a-z]?/
。但第二个例子不起作用。
编辑:输入可以预期按正确的顺序(h,m,s)进行排序。这些值是以字符串还是数字的形式存储也没关系。
编辑2:很抱歉更新太晚了,实际上输入的13-
部分也可以忽略,但它没有太大区别,无论如何都可以很容易地进行调整。
这应该可以回答您的问题:
const labelMap = { h: 'hours', m: 'minutes', s: 'seconds' };
[
"13-4h50m2s",
"13-2s4h",
"13-50m"
].forEach((str) => {
let obj = { hours: 0, minutes: 0, seconds: 0 };
str.replace(/(d+)([hms])/g, (m, p1, p2) => {
obj[labelMap[p2]] = parseInt(p1, 10);
});
console.log(JSON.stringify(obj));
});
输出:
{"hours":4,"minutes":50,"seconds":2}
{"hours":4,"minutes":0,"seconds":2}
{"hours":0,"minutes":50,"seconds":0}
注:
labelMap
从输入单元映射到所需的输出对象键- 使用一个没有返回的字符串替换,它只用于迭代我们想要的模式:
/(d+)([hms])/g
- 替换函数根据数字和单位组成对象
您可以匹配数字和后缀,然后使用Object.fromEntries
将结果转换为对象。使用具有排列语法的对象初始化程序为未填充的属性获取0:
const parse = s =>
({h: 0, m: 0, s: 0, ...
Object.fromEntries(s.match(/d+[msh]/g).map(m => [m[m.length-1], parseInt(m)]))
});
let inputs = [
"13-4h50m2s",
"13-2s4h",
"13-50m"
];
console.log(inputs.map(parse));
注意:这会重复使用单个字母h、m、s作为属性名称。
所以我实际上得到了一个我满意的工作解决方案:
const inputs = [
'1h2m3s',
'4h5m',
'6m',
'7h8s',
'9m10s'
]
const re = /(?<hours>d+(?=h))?[hms]?(?<minutes>d+(?=m))?[hms]?(?<seconds>d+(?=s))?/
for (str of inputs) {
const match = re.exec(str)
const {hours = 0, minutes = 0, seconds = 0} = match.groups
console.log({hours,minutes,seconds})
}
字符串和数字是混合的,但这没关系,只要h、m、s的顺序正确,它就可以工作。
正则表达式
我使用了可选的命名捕获组,并对相应的时间单位进行了前瞻性处理,然后在两者之间使用了可选的[hms]
字符集。