Rust数据解析库fundu的使用,fundu提供高效灵活的数据格式解析与转换功能

Rust数据解析库fundu的使用,fundu提供高效灵活的数据格式解析与转换功能

fundu是一个灵活且快速的Rust库,用于将字符串转换为Duration类型。它解析成自己的Duration类型,但提供了转换为std::time::Duration、chrono::Duration和time::Duration的方法。

主要特性

  1. 精确性:没有浮点计算,输入被精确解析
  2. 高性能:解析速度极快
  3. 可定制性:时间单位、数字格式等可轻松配置
  4. 合理限制:持续时间在Duration::MAX处饱和
  5. 负持续时间:可配置解析负持续时间
  6. 错误处理:错误信息清晰易懂

安装

在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),
        }
    }
}

这个完整示例展示了:

  1. 创建自定义时间单位解析器,支持中英文单位
  2. 允许负值和分隔符
  3. 支持多种时间格式组合
  4. 详细的错误处理
  5. 多种时间单位转换
  6. 支持科学计数法表示的时间值

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在设计上注重性能,以下是一些使用建议:

  1. 对于重复使用,创建一次解析器并重复使用
  2. 如果不需要某些时间单位,在构建解析器时排除它们
  3. 对于已知格式,使用最严格的解析器配置

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());
}

这个完整示例展示了:

  1. 自定义时间解析器的创建和使用
  2. 处理带有负值的时间字符串
  3. 自定义数字解析器(使用^作为指数符号)
  4. 多种数字格式的解析尝试
  5. 复杂时间格式的组合解析
  6. 全面的错误处理

输出结果示例:

=== 时间解析演示 ===
解析成功!
总秒数: 183615
总纳秒: 183615000000000

=== 数字解析演示 ===
'3.14' 解析为: 3.14
'-1.5^3' 解析为: -1500
'0x1F' 解析失败: Number parsing error
'invalid' 解析失败: Number parsing error

=== 复杂时间格式解析 ===
1.5小时 + 30分钟 + 500毫秒 = 5430.5秒
回到顶部