问题描述
我需要允许用户键入这样的字符串:
1m 3w 4d 22h 6m 3s
…,然后将其转换为ISO 8601持续时间格式,如下所示:
P1M3W4DT22H6M3S
甚至应该允许他们写出更短的符号,例如:
10d 12h
我什至不知道从哪里开始,而且似乎找不到任何有助于这些转换的库。我可以使用Moment将从 ISO 8601持续时间格式转换,但不能将转换为。
建议?
我试图删除空格,但是当然我想念之前的T
:
`P${duration.toupperCase().replace(/\s/g,'')}`
解决方法
删除空格并大写字母后,可以使用正则表达式\d+H?\d*M?\d*S?$
捕获输入的时间部分(如果有的话)。这确定了“ T”定界符的插入点:
const toDuration = s => "P" + s.toUpperCase(s).replace(/\s/g,"")
.replace(/\d+H?\d*M?\d*S?$/,"T$&");
console.log(toDuration("1m 3w 4d 22h 6m 3s"));
console.log(toDuration("10d 12h"));
console.log(toDuration("10m"));
console.log(toDuration("1y 8w 3d"));
console.log(toDuration("2m 12h"));
做出一些假设:
- 如果输入对“ m”(月或分钟)的含义有歧义,则将其解释为分钟。
- 不需要更改输入中各部分的顺序即可得出有效的期间符号。
- 输入遵循示例中给出的格式。此处没有输入验证。
如果要包括验证,则可以这样扩展:
const toDuration = s => /^(\d+y\s*)?(\d+m\s*)?(\d+w\s*)?(\d+d\s*)?(\d+h\s*)?(\d+m\s*)?(\d+s\s*)?$/i.test(s)
? "P" + s.toUpperCase(s).replace(/\s/g,"")
.replace(/\d+H?\d*M?\d*S?$/,"T$&")
: ""; // indicates bad format
console.log(toDuration("1m 3w 4d 22h 6m 3s"));
console.log(toDuration("10d 12h"));
console.log(toDuration("10m"));
console.log(toDuration("1y 8w 3d"));
console.log(toDuration("2m 12h"));
console.log(toDuration("bad12 format"));
,
如果您只想念T
后的D
分隔符,只需添加.replace('D','DT')}
。
let duration = '1m 3w 4d 22h 6m 3s'
`P${duration.toUpperCase().replace(/\s/g,'').replace('D','DT')}`
// gives 'P1M3W4D22H6M3S'
但这仅适用于静态输入格式。
要同时解析完整和不完整的输入,您需要按类型对其进行解析。
const parseDuration = duration => {
const keys = ['Y','M','W','D','H','MIN','S']
if (!duration || typeof duration !== 'string')
throw "Empty input"
let parsed = {}
// split entries by space and process them
duration.split(/\s+/).map(r => {
// get length (number) and type for each entry
let [_,len,type] = r.match(/^(\d+)(\w+)$/)
type = type.toUpperCase()
// assume M means minutes if either of W,D or H is set
if (type === 'M' && (parsed['W'] || parsed['D'] || parsed['H']))
type = 'MIN'
// asign length by type
if (len && keys.includes(type))
parsed[type] = len
})
if (!Object.keys(parsed).length)
throw new Error("Empty input")
// set all undefined types to zero
for (const k of keys)
parsed[k] = parseInt(parsed[k]) || 0
// format to ISO 8601 duration
return `P${parsed.Y}Y${parsed.M}M${parsed.W}W${parsed.D}DT${parsed.H}H${parsed.MIN}M${parsed.S}S`
}
try {
console.log(parseDuration('1m 3w 4d 22h 6m 3s'))
} catch {
console.warn('failed to parse')
}
// P0Y1M3W4DT22H6M3S
try {
console.log(parseDuration('3w 12h 10m'))
} catch {
console.warn('failed to parse')
}
// P0Y0M3W0DT12H10M0S
try {
console.log(parseDuration('1bullshit'))
} catch {
console.warn('failed to parse')
}
// fails
try {
console.log(parseDuration(''))
} catch {
console.warn('failed to parse')
}
// fails
示例经过修改以包含基本语法验证