代码之家  ›  专栏  ›  技术社区  ›  Ross MacArthur

反序列化Rust中字符串的key=value列表的最佳方法

  •  3
  • Ross MacArthur  · 技术社区  · 6 年前

    field1=something
    field2=556
    field3=true
    field4=10.0.0.1
    

    每个字段的类型将始终相同,但并不总是存在。顺序也可以改变。

    struct Data {
        field1: Option<String>,
        field2: Option<u32>,
        field3: Option<bool>,
        field4: Option<std::net::Ipv4Addr>
    }
    

    最好的方法是什么?我应该使用 serde 大木箱

    https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=e16244e50492aa218217cb44d5f27cfe

    但我如何将其泛化为多个结构?

    use std::net::Ipv4Addr;
    use std::str::FromStr;
    
    #[derive(Debug)]
    struct Data {
        field1: Option<String>,
        field2: Option<u32>,
        field3: Option<bool>,
        field4: Option<Ipv4Addr>,
    }
    
    fn main() {
        let mut s = "field1=something
    field2=556
    field3=true
    field4=10.0.0.1"
            .to_string();
    
        let mut field1 = None;
        let mut field2 = None;
        let mut field3 = None;
        let mut field4 = None;
    
        let lines: Vec<_> = s.split("\n").collect();
    
        for line in lines {
            let pair: Vec<_> = line.splitn(2, "=").collect();
            let key = pair[0];
            let value = pair[1];
    
            match key {
                "field1" => {
                    field1 = Some(value.to_owned());
                }
                "field2" => {
                    field2 = Some(u32::from_str(value).unwrap());
                }
                "field3" => {
                    field3 = match value {
                        "true" => Some(true),
                        "false" => Some(false),
                        _ => None
                    };
                }
                "field4" => {
                    field4 = Some(Ipv4Addr::from_str(value).unwrap());
                }
                _ => {}
            }
        }
    
        println!(
            "{:?}",
            Data {
                field1,
                field2,
                field3,
                field4
            }
        );
    }
    
    1 回复  |  直到 6 年前
        1
  •  2
  •   attdona    6 年前

    概括多个目标结构的一种方法可能是使用 serde

    对于自定义格式,必须实现反序列化程序, 但不是这样的实施

    您的格式似乎是 TOML 格式:如果是这种情况,请使用 toml .

    #[macro_use]
    extern crate serde_derive;
    
    #[derive(Serialize, Deserialize, Debug)]
    struct Data {
        field1: Option<String>,
        field2: Option<u32>,
        field3: Option<bool>,
        field4: Option<std::net::Ipv4Addr>
    }
    
    fn main() {
        let serialized = r#"
    field1="something"
    field2=556
    field3=true
    field4="10.0.0.1"
    "#;
    
        let deserialized: Data = toml::from_str(&serialized).unwrap();
        println!("{:?}", deserialized);
    
    }
    

    如果您的格式与“标准”不完全兼容,请在反序列化之前寻找转换编码数据的方法:例如,如果 field1 field4 regex

    #[macro_use]
    extern crate serde_derive;
    
    use std::borrow::Cow;
    use regex::{Captures, Regex};
    
    #[derive(Serialize, Deserialize, Debug)]
    struct Data {
        field1: Option<String>,
        field2: Option<u32>,
        field3: Option<bool>,
        field4: Option<std::net::Ipv4Addr>,
    }
    
    fn reformat_string(before: &str) -> Cow<str> {
        let matcher : Regex = Regex::new(
                r"(?P<f>field1|field4)=(?P<val>[\w.]+)"
                ).unwrap();
    
        matcher.replace_all(before, |cap: &Captures| {
            let mut buff = String::new();
            if &cap[1] == "field1" || &cap[1] == "field4" {
                cap.expand("$f='$val'", &mut buff);
            }
            Cow::Owned(buff)
        })
    }
    
    
    fn main() {
        let serialized = r#"
        field1=something
        field2=556
        field3=true
        field4=10.0.0.1
        "#;
    
    
        let transformed = reformat_string(serialized);
        let deserialized: Data = toml::from_str(&transformed).unwrap();
        println!("{:?}", deserialized);
    }