如何在 Objective C 中解析 ISO-8601 持续时间?
我正在寻找一种简单的方法来解析 Objective C 中包含 ISO-8601 duration 的字符串。结果应该是像 NSTimeInterval
这样可用的东西。
ISO-8601 持续时间示例:P1DT13H24M17S
,表示 1 天 13 小时 24 分 17 秒。
I'm looking for an easy way to parse a string that contains an ISO-8601 duration in Objective C. The result should be something usable like a NSTimeInterval
.
An example of an ISO-8601 duration: P1DT13H24M17S
, which means 1 day, 13 hours, 24 minutes and 17 seconds.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(12)
Swift3,4,5 实现:
https://github.com/ Igor-Palaguta/YoutubeEngine/blob/master/Source/YoutubeEngine/Parser/NSDateComponents%2BISO8601.swift
示例:
let Components = try DateComponents(ISO8601String: "P1Y2M3DT4H5M6S")
测试:
https://github.com/Igor-Palaguta/ YoutubeEngine/blob/master/Tests/YoutubeEngineTests/ISO8601DurationTests.swift
更新:修复了 DougSwith 案例
“P3W3DT20H31M21”
Swift3,4,5 implementation:
https://github.com/Igor-Palaguta/YoutubeEngine/blob/master/Source/YoutubeEngine/Parser/NSDateComponents%2BISO8601.swift
Example:
let components = try DateComponents(ISO8601String: "P1Y2M3DT4H5M6S")
Tests:
https://github.com/Igor-Palaguta/YoutubeEngine/blob/master/Tests/YoutubeEngineTests/ISO8601DurationTests.swift
Update: fixed for DougSwith case
"P3W3DT20H31M21"
纯 Objective C 版本...
A pure Objective C version...
此版本解析每个 YouTube 持续时间,没有错误。
重要:此版本使用 ARC。
This version parse every youtube duration without errors.
Important: This version use ARC.
如果您确切知道将获得哪些字段,则可以使用一次
sscanf()
调用:如果任何字段可能被省略,则您需要在解析时更加聪明一些,例如:
If you know exactly which fields you'll be getting, you can use one invocation of
sscanf()
:If any of the fields might be omitted, you'll need to be a little smarter in your parsing, e.g.:
稍微修改用户
Sergei Pekar的功能
slightly modifying function of the user
Sergei Pekar
这是一个 swift 的例子:
(仅适用于小时、分钟和秒)
Here is an example for swift:
(only for hours, minutes and seconds)
这是 swift 3 版本的 headkaze 示例:这种格式最适合我的情况:
Here is swift 3 version of headkaze example: This format was most suitable in my case:
我查阅了这篇维基百科文章,以了解 ISO-8601 实际工作原理的参考。 我不是 Cocoa 专家,但我敢打赌,如果您可以解析该字符串并提取组件小时、分钟、秒、日等,那么将其放入 NSTimeInterval 应该很容易。 棘手的部分是解析它。 我可能会这样做:
首先,将字符串分成两个单独的字符串:一个代表日期,一个代表时间。 NSString 有一个实例方法 ComponentsSeparatedByString:NSString,它返回原始 NSString 的子字符串的 NSArray,这些子字符串由您传入的参数分隔。它看起来像这样:
接下来,在 iso8601Parts 的第一个元素中搜索每个可能的日持续时间指示器( Y、M、W 和 D)。 当你找到一个时,抓住所有前面的数字(可能还有小数点),将它们转换为浮点数,并将它们存储在某个地方。 请记住,如果只有时间元素,则 iso8601Parts[0] 将是空字符串。
然后,执行相同的操作,在 iso8601Parts 的第二个元素中查找时间部分,以获取可能的时间指示器(H、M、S)。 请记住,如果只有一天组件(即原始字符串中没有“T”字符),则 iso8601Parts 的长度仅为 1,并且尝试访问第二个元素将导致越界异常。
NSTimeInterval 只是一个存储秒数的长整数,因此将您提取的各个部分转换为秒,将它们添加在一起,将它们存储在您的 NSTimeInterval 中,然后就可以了。
抱歉,我知道您要求一种“简单”的方法来做到这一点,但根据我(诚然)的搜索和 API 知识,这是最简单的方法。
I looked up this Wikipedia article for a reference to how ISO-8601 actually works. I'm no Cocoa expert, but I'm betting if you can parse that string and extract the component hour, minute, second, day, etc., getting it in to an NSTimeInterval should be easy. The tricky part is parsing it. I'd probably do it something like this:
First, split the string in to two separate strings: one representing the days, and one representing the times. NSString has an instance method componentsSeparatedByString:NSString that returns an NSArray of substrings of your original NSString separated by the parameter you pass in. It would look something like this:
Next, search the first element of iso8601Parts for each of the possible day duration indicators (Y, M, W, and D). When you find one, grab all the preceeding digits (and possibly a decimal point), cast them to a float, and store them somewhere. Remember that if there was only a time element, then iso8601Parts[0] will be the empty string.
Then, do the same thing looking for time parts in the second element of iso8601Parts for possible time indicators (H, M, S). Remember that if there was only a day component (that is, there was no 'T' character in the original string), then iso8601Parts will only be of length one, and an attempt to access the second element will cause an out of bounds exception.
An NSTimeInterval is just a long storing a number of seconds, so convert the individual pieces you pulled out in to seconds, add them together, store them in your NSTimeInterval, and you're set.
Sorry, I know you asked for an "easy" way to do it, but based on my (admittedly light) searching around and knowledge of the API, this is the easiest way to do it.
快速而肮脏的实施
Quick and dirty implementation
已经有答案了,但我最终使用 NSScanner 实现了另一个版本。 此版本忽略年份和月份,因为它们无法转换为秒数。
There are answers already, but I ended up implementing yet another version using
NSScanner
. This version ignores year and month since they cannot be converted to number of seconds.现在在 Swift 中! (是的,它有点长,但它处理所有情况和单数/复数)。
处理年、月、周、日、小时、分钟和秒!
Now in
Swift
! (Yes it's a little long, but it handles all cases and singular/plural).Handles Years, Months, Weeks, Days, Hours, Minutes, and Seconds!
Swift 4.2 版本
适用于年、月、日、小时、分钟、秒。
秒可以是浮点数。
持续时间结构:
}
Swift 4.2 version
Works with years, months, days, hours, minutes, seconds.
Seconds can be float number.
Duration struct:
}