Rust数据解析库fundu的使用,fundu提供高效灵活的数据格式解析与转换功能
Rust数据解析库fundu的使用,fundu提供高效灵活的数据格式解析与转换功能
fundu是一个灵活且快速的Rust库,用于将字符串转换为Duration类型。它解析成自己的Duration类型,但提供了转换为std::time::Duration、chrono::Duration和time::Duration的方法。
主要特性
- 精确性:没有浮点计算,输入被精确解析
- 高性能:解析速度极快
- 可定制性:时间单位、数字格式等可轻松配置
- 合理限制:持续时间在Duration::MAX处饱和
- 负持续时间:可配置解析负持续时间
- 错误处理:错误信息清晰易懂
安装
在Cargo.toml中添加:
[dependencies]
fundu = "2.0.1"
使用示例
基本用法
use std::time::Duration;
use fundu::parse_duration;
let input = "1.0e2s";
assert_eq!(parse_duration(input).unwrap(), Duration::new(100, 0));
自定义时间单位
use fundu::{Duration, DurationParser};
let input = "3m";
assert_eq!(
DurationParser::with_all_time_units().parse(input).unwrap(),
Duration::positive(180, 0)
);
无时间单位配置(默认秒)
use fundu::{Duration, DurationParser};
let input = "1.0e2";
assert_eq!(
DurationParser::without_time_units().parse(input).unwrap(),
Duration::positive(100, 0)
);
自定义时间单位解析器
use fundu::TimeUnit::*;
use fundu::{Duration, DurationParser};
let parser = DurationParser::with_time_units(&[NanoSecond, Minute, Hour]);
assert_eq!(parser.parse("9e3ns").unwrap(), Duration::positive(0, 9000));
assert_eq!(parser.parse("10m").unwrap(), Duration::positive(600, 0));
assert_eq!(parser.parse("1.1h").unwrap(), Duration::positive(3960, 0));
assert_eq!(parser.parse("7").unwrap(), Duration::positive(7, 0));
设置默认时间单位
use fundu::TimeUnit::*;
use fundu::{Duration, DurationParser};
assert_eq!(
DurationParser::without_time_units()
.default_unit(MilliSecond)
.parse("1000")
.unwrap(),
Duration::positive(1, 0)
);
完全自定义时间单位标识符
use fundu::TimeUnit::*;
use fundu::{CustomTimeUnit, CustomDurationParser, Duration};
let parser = CustomDurationParser::with_time_units(&[
CustomTimeUnit::with_default(MilliSecond, &["χιλιοστό του δευτερολέπτου"]),
CustomTimeUnit::with_default(Second, &["s", "secs"]),
CustomTimeUnit::with_default(Hour, &["⏳"]),
]);
assert_eq!(parser.parse(".3χιλιοστό του δευτερολέπτου"), Ok(Duration::positive(0, 300_000)));
assert_eq!(parser.parse("1e3secs"), Ok(Duration::positive(1000, 0)));
assert_eq!(parser.parse("1.1⏳"), Ok(Duration::positive(3960, 0)));
错误处理
use fundu::DurationParser;
assert_eq!(
DurationParser::without time_units()
.parse("1y")
.unwrap_err()
.to_string(),
"Time unit error: No time units allowed but found: 'y' at column 1"
);
自定义数字格式
use fundu::TimeUnit::*;
use fundu::{Duration, DurationParser, ParseError};
const PARSER: DurationParser = DurationParser::builder()
.time_units(&[NanoSecond])
.allow_time_unit_delimiter()
.number_is_optional()
.disable_fraction()
.disable_exponent()
.build();
assert_eq!(PARSER.parse("ns").unwrap(), Duration::positive(0, 1));
assert_eq!(
PARSER.parse("1000\t\n\r ns").unwrap(),
Duration::positive(0, 1000)
);
assert_eq!(
PARSER.parse("1.0ns").unwrap_err(),
ParseError::Syntax(1, "No fraction allowed".to_string())
);
assert_eq!(
PARSER.parse("1e9ns").unwrap_err(),
ParseError::Syntax(1, "No exponent allowed".to_string())
);
解析多个持续时间
use fundu::{Duration, DurationParser};
let parser = DurationParser::builder()
.default_time_units()
.parse_multiple(Some(&["and"]))
.build();
assert_eq!(
parser.parse("1.5h 2e+2ns"),
Ok(Duration::positive(5400, 200))
);
assert_eq!(
parser.parse("55s500ms"),
Ok(Duration::positive(55, 500_000_000))
);
完整示例
下面是一个更完整的示例,展示如何使用fundu进行复杂的时间解析:
use fundu::{CustomTimeUnit, CustomDurationParser, Duration};
use fundu::TimeUnit::*;
fn main() {
// 创建完全自定义的解析器
let parser = CustomDurationParser::with_time_units(&[
CustomTimeUnit::with_default(NanoSecond, &["纳秒", "ns"]),
CustomTimeUnit::with_default(MicroSecond, &["微秒", "μs"]),
CustomTimeUnit::with_default(MilliSecond, &["毫秒", "ms"]),
CustomTimeUnit::with_default(Second, &["秒", "s"]),
CustomTimeUnit::with_default(Minute, &["分钟", "min"]),
CustomTimeUnit::with_default(Hour, &["小时", "h"]),
CustomTimeUnit::with_default(Day, &["天", "d"]),
])
.allow_negative()
.allow_time_unit_delimiter()
.parse_multiple(Some(&["和", "与"]));
// 测试各种时间格式
let test_cases = vec![
"1.5小时",
"30分钟",
"-2天",
"1.5e3毫秒",
"1 天 和 2 小时",
"30秒与500毫秒",
"1e3纳秒",
"无效时间格式",
];
for input in test_cases {
match parser.parse(input) {
Ok(duration) => {
println!("成功解析 '{}'", input);
println!("解析结果: {:?}", duration);
println!("转换为秒: {}", duration.as_secs());
println!("转换为纳秒: {}", duration.subsec_nanos());
println!("总纳秒: {}", duration.as_nanos());
println!("----------------------");
}
Err(e) => println!("解析 '{}' 失败: {}", input, e),
}
}
}
这个完整示例展示了:
- 创建自定义时间单位解析器,支持中英文单位
- 允许负值和分隔符
- 支持多种时间格式组合
- 详细的错误处理
- 多种时间单位转换
- 支持科学计数法表示的时间值
fundu的强大之处在于它的高度可定制性,可以轻松适应各种时间格式解析需求,同时保持极高的解析性能和精确性。
1 回复
Rust数据解析库fundu的使用指南
fundu是一个高效灵活的Rust数据格式解析与转换库,专注于解析各种格式的时间字符串和数字数据。它提供了强大的解析能力,同时保持高性能。
主要特性
- 支持多种时间格式解析(如"3h 45m"、“1d 2h 30s”)
- 可解析各种数字格式(包括科学计数法)
- 高度可配置的解析规则
- 零拷贝解析
- 良好的错误处理
基本使用方法
添加依赖
首先在Cargo.toml中添加fundu依赖:
[dependencies]
fundu = "0.5"
解析时间字符串示例
use fundu::TimeUnit::*;
use fundu::{Duration, TimeParser, TimeUnit};
fn main() {
// 创建解析器配置
let parser = TimeParser::new();
// 解析简单时间字符串
let duration = parser.parse("1h 30m").unwrap();
println!("总秒数: {}", duration.as_secs()); // 输出: 5400
// 解析复杂时间字符串
let duration = parser.parse("1d 2h 30m 15s 500ms").unwrap();
println!("总纳秒: {}", duration.as_nanos());
}
自定义解析规则
use fundu::{Duration, TimeParserBuilder, TimeUnit::*};
fn main() {
// 构建自定义解析器
let parser = TimeParserBuilder::new()
.time_units(&[MicroSecond, MilliSecond, Second, Minute])
.allow_negative()
.build();
match parser.parse("-1.5m 30s") {
Ok(duration) => println!("解析结果: {:?}", duration),
Err(e) => println!("解析错误: {}", e),
}
}
数字解析示例
fundu也可以用于通用数字解析:
use fundu::NumParser;
fn main() {
let parser = NumParser::new();
// 解析整数
let num = parser.parse("42").unwrap();
println!("解析结果: {}", num); // 42
// 解析科学计数法
let num = parser.parse("1.23e4").unwrap();
println!("解析结果: {}", num); // 12300
// 解析十六进制
let num = parser.parse("0xff").unwrap();
println!("解析结果: {}", num); // 255
}
高级用法
自定义数字格式
use fundu::NumParserBuilder;
fn main() {
let parser = NumParserBuilder::new()
.exponent(b'^') // 使用'^'代替'e'作为指数符号
.build();
let num = parser.parse("1.5^3").unwrap();
println!("解析结果: {}", num); // 1500
}
错误处理
use fundu::TimeParser;
fn main() {
let parser = TimeParser::new();
match parser.parse("1x 2y") {
Ok(duration) => println!("解析成功: {:?}", duration),
Err(e) => println!("解析失败: {}", e),
// 输出: 解析失败: Unknown time unit: 'x'
}
}
性能提示
fundu在设计上注重性能,以下是一些使用建议:
- 对于重复使用,创建一次解析器并重复使用
- 如果不需要某些时间单位,在构建解析器时排除它们
- 对于已知格式,使用最严格的解析器配置
fundu是一个强大而灵活的工具,特别适合需要解析各种非标准时间或数字格式的应用场景。其API设计直观,同时提供了足够的配置选项来满足各种需求。
完整示例demo
以下是一个结合时间解析和数字解析的完整示例:
use fundu::{Duration, TimeParserBuilder, TimeUnit::*};
use fundu::NumParserBuilder;
fn main() {
// 时间解析演示
println!("=== 时间解析演示 ===");
let time_parser = TimeParserBuilder::new()
.time_units(&[Second, Minute, Hour, Day])
.allow_negative()
.build();
match time_parser.parse("2d 3h -30m 15s") {
Ok(duration) => {
println!("解析成功!");
println!("总秒数: {}", duration.as_secs());
println!("总纳秒: {}", duration.as_nanos());
},
Err(e) => println!("时间解析错误: {}", e),
}
// 数字解析演示
println!("\n=== 数字解析演示 ===");
let num_parser = NumParserBuilder::new()
.exponent(b'^') // 使用自定义指数符号
.build();
let numbers = vec!["3.14", "-1.5^3", "0x1F", "invalid"];
for num_str in numbers {
match num_parser.parse(num_str) {
Ok(num) => println!("'{}' 解析为: {}", num_str, num),
Err(e) => println!("'{}' 解析失败: {}", num_str, e),
}
}
// 复杂时间格式解析
println!("\n=== 复杂时间格式解析 ===");
let complex_time_parser = TimeParserBuilder::new()
.default_unit(Second) // 默认单位为秒
.time_units(&[MilliSecond, Second, Minute, Hour])
.build();
let complex_duration = complex_time_parser.parse("1.5h 30m 500ms").unwrap();
println!("1.5小时 + 30分钟 + 500毫秒 = {}秒", complex_duration.as_secs_f64());
}
这个完整示例展示了:
- 自定义时间解析器的创建和使用
- 处理带有负值的时间字符串
- 自定义数字解析器(使用^作为指数符号)
- 多种数字格式的解析尝试
- 复杂时间格式的组合解析
- 全面的错误处理
输出结果示例:
=== 时间解析演示 ===
解析成功!
总秒数: 183615
总纳秒: 183615000000000
=== 数字解析演示 ===
'3.14' 解析为: 3.14
'-1.5^3' 解析为: -1500
'0x1F' 解析失败: Number parsing error
'invalid' 解析失败: Number parsing error
=== 复杂时间格式解析 ===
1.5小时 + 30分钟 + 500毫秒 = 5430.5秒