当前位置: 首页 > news >正文

【iso8601库】ISO 8601 低层解析器详解(parsers.rs)

parsers.rs是一个基于 nom 解析器组合库实现的 ISO 8601 格式解析器,支持 no_std 环境。

整体架构

设计理念

  • 低层解析器: 提供基础的解析组件,可以组合使用
  • 保留剩余输入: 允许继续解析其他内容或错误恢复
  • 模块化设计: 每个解析器负责特定的格式部分

核心工具函数

数字解析函数

fn take_digits(i: &[u8]) -> IResult<&[u8], u32> {let (i, digits) = take_while(AsChar::is_dec_digit).parse(i)?;// 解析数字字符串为 u32
}

功能: 提取连续数字并转换为整数

fn take_n_digits(i: &[u8], n: usize) -> IResult<&[u8], u32> {let (i, digits) = take_while_m_n(n, n, AsChar::is_dec_digit)(i)?;// 精确提取 n 位数字
}

功能: 精确提取指定长度的数字

fn n_digit_in_range(i: &[u8], n: usize, range: impl core::ops::RangeBounds<u32>) -> IResult<&[u8], u32> {// 提取数字并验证范围
}

功能: 提取数字并验证其有效性(如月份 1-12)

符号解析

fn sign(i: &[u8]) -> IResult<&[u8], i32> {alt((tag("-"), tag("+"))).map(|s: &[u8]| match s {b"-" => -1,_ => 1,}).parse(i)
}

功能: 解析 +- 符号,返回乘数因子

日期解析器

年份解析

fn date_year(i: &[u8]) -> IResult<&[u8], i32> {(opt(sign), |i| take_n_digits(i, 4)).map(|(s, year)| s.unwrap_or(1) * year as i32).parse(i)
}

支持格式: +2023, -2023, 2023

三种日期格式支持

1. 日历日期 (YMD)
fn date_ymd(i: &[u8]) -> IResult<&[u8], Date> {(date_year, opt(tag("-")), date_month, opt(tag("-")), date_day).map(|(year, _, month, _, day)| Date::YMD { year, month, day }).parse(i)
}

格式: YYYY-MM-DDYYYYMMDD

2. 序数日期 (Ordinal)
fn date_ordinal(i: &[u8]) -> IResult<&[u8], Date> {separated_pair(date_year, opt(tag("-")), date_ord_day).map(|(year, ddd)| Date::Ordinal { year, ddd }).parse(i)
}

格式: YYYY-DDD(年-年内第几天)

3. 周日期 (Week)
fn date_iso_week(i: &[u8]) -> IResult<&[u8], Date> {(date_year, (opt(tag("-")), tag("W")), date_week, opt(tag("-")), date_week_day).map(|(year, _, ww, _, d)| Date::Week { year, ww, d }).parse(i)
}

格式: YYYY-Www-D(年-周数-周内天数)

时间解析器

时间组件解析

fn time_hour(i: &[u8]) -> IResult<&[u8], u32>    // 0-24
fn time_minute(i: &[u8]) -> IResult<&[u8], u32>  // 0-59  
fn time_second(i: &[u8]) -> IResult<&[u8], u32>  // 0-60(支持闰秒)

毫秒解析

fn fraction_millisecond(i: &[u8]) -> IResult<&[u8], u32> {let (i, mut digits) = take_while(AsChar::is_dec_digit).parse(i)?;// 处理 1-3 位小数,转换为毫秒
}

转换规则:

  • "" → 0
  • "1" → 100
  • "12" → 120
  • "123" → 123
  • "1234" → 123(截断)

完整时间解析

pub fn parse_time(i: &[u8]) -> IResult<&[u8], Time> {(time_hour,                                         // HHopt(tag(":")),                                     // :time_minute,                                       // MMopt(preceded(opt(tag(":")), time_second)),         // [SS]opt(preceded(one_of(",."), fraction_millisecond)), // [.(m*)]opt(alt((timezone_hour, timezone_utc))),           // [(Z|+...|-...)]).map(|(h, _, m, s, ms, z)| {// 构建 Time 结构体})
}

支持格式: HH:MM:SS.sss+HH:MM

时区解析

fn timezone_hour(i: &[u8]) -> IResult<&[u8], (i32, i32)> {(sign, time_hour, opt(preceded(opt(tag(":")), time_minute))).map(|(s, h, m)| (s * (h as i32), s * (m.unwrap_or(0) as i32))).parse(i)
}fn timezone_utc(input: &[u8]) -> IResult<&[u8], (i32, i32)> {tag("Z").map(|_| (0, 0)).parse(input)
}

支持格式: Z, +08:00, -05:30

日期时间组合解析

pub fn parse_datetime(i: &[u8]) -> IResult<&[u8], DateTime> {separated_pair(parse_date, tag("T"), parse_time).map(|(d, t)| DateTime { date: d, time: t }).parse(i)
}

格式: Date + "T" + Time

持续时间解析

ISO 8601 持续时间格式

1. 组件格式 (YMDHMS)
fn duration_ymdhms(i: &[u8]) -> IResult<&[u8], Duration> {preceded(tag("P"), ...).map(|(y, mo, d, time)| {Duration::YMDHMS {year: y.unwrap_or(0),month: mo.unwrap_or(0),day: d.unwrap_or(0),hour: h,minute: mi,second: s,millisecond: ms,}})
}

格式: P[nY][nM][nD][T[nH][nM][nS]]

示例:

  • P1Y2M3DT4H5M6S = 1年2月3天4小时5分钟6秒
  • PT1H30M = 1小时30分钟
2. 周格式
fn duration_weeks(i: &[u8]) -> IResult<&[u8], Duration> {preceded(tag("P"), duration_week).map(Duration::Weeks).parse(i)
}

格式: PnW

示例: P4W = 4周

3. 日期时间格式
fn duration_datetime(i: &[u8]) -> IResult<&[u8], Duration> {// 解析 PYYYY-MM-DDTHH:MM:SS 格式
}

格式: PYYYY-MM-DDTHH:MM:SS

设计优势

  1. 组合性: 使用 nom 组合器,易于扩展和维护
  2. 错误恢复: 保留剩余输入,支持更好的错误处理
  3. 性能: 直接操作字节,避免字符串分配
  4. no_std 支持: 适用于嵌入式系统
  5. 完整性: 支持 ISO 8601 主要格式变体

使用示例

// 低层使用 - 保留剩余输入
let (remaining, date) = parse_date(b"2023-02-18 extra data")?;
// remaining = b" extra data"// 组合解析器
let (remaining, datetime) = parse_datetime(b"2023-02-18T17:08:08Z end")?;// 错误处理
match parse_time(b"25:61:00") {Ok((remaining, time)) => { /* 成功 */ }Err(nom::Err::Error(e)) => { /* 解析错误 */ }Err(nom::Err::Incomplete(_)) => { /* 需要更多输入 */ }
}

这个解析器库提供了灵活、高效的 ISO 8601 格式解析能力,特别适合需要精细控制解析过程的场景。

http://www.dtcms.com/a/574525.html

相关文章:

  • 有什么网站可以接手工加工做在线免费看电视剧的网站
  • 类似享设计的网站做贸易选哪家网站
  • 算法笔记 10
  • 锛网站开封seo公司
  • Linux 进程资源占用分析指南
  • 电子商务网站建设评估的指标wordpress程序图片打开慢
  • 网站开发时如何设计英文版本山东手机网站建设
  • 算法题种类与解题思路全面指南:基于LeetCode Hot 100与牛客Top 101
  • Web开发身份认证技术解析
  • 做汽车网站怎么挣钱吗深圳网站建设公司好
  • 网站建设素材网页apache 创建网站
  • 虚函数指针与虚函数表:C++多态的实现奥秘
  • 小说类网站怎么做建设推广营销型网站应该注意什么
  • ubuntu 安装 SRS (Simple RTMP Server) 是一个开源的流媒体服务器
  • 怎么自己设计网站外贸公司 网站
  • 【仓颉纪元】仓颉鸿蒙应用深度开发:待办事项 App 全流程实战
  • 领英被封?账号受限该怎么处理?
  • 信誉好的镇江网站建设网站备案名称中国开头
  • 【C语言】localtime和localtime_r;strftime和strftime_l
  • 扁平化设计网站代码打开网站后直接做跳转
  • Go 语言依赖注入实战指南:从基础到高级实践
  • 全场景自动化 Replay 技术:金仓 KReplay 如何攻克数据库迁移 “难验证“ 难题
  • 阳新县建设局网站win2008系统asp网站建设
  • 网站域名分几种新东方雅思培训机构官网
  • 网站怎么样做不违规学科基地网站建设
  • MySQL-4-视图和索引
  • 电脑被捆绑软件缠上?3 步根治卡顿弹窗~
  • Linux时间处理与系统时间管理详解
  • 上饶建设局网站开封到濮阳
  • 织梦网站动态华为云自助建站