Rust有什么像scanf吗?

时间:2015-06-25 09:45:44

标签: string parsing rust

我需要在每行解析一个文件

<string><space><int><space><float>

e.g。

abce 2 2.5

在C中我会这样做:

scanf("%s%d%f", &s, &i, &f);

如何在Rust中轻松和惯用地执行此操作?

4 个答案:

答案 0 :(得分:17)

标准库不提供此功能。你可以用宏编写自己的。

macro_rules! scan {
    ( $string:expr, $sep:expr, $( $x:ty ),+ ) => {{
        let mut iter = $string.split($sep);
        ($(iter.next().and_then(|word| word.parse::<$x>().ok()),)*)
    }}
}

fn main() {
    let output = scan!("2 false fox", char::is_whitespace, u8, bool, String);
    println!("{:?}", output); // (Some(2), Some(false), Some("fox"))
}

宏的第二个输入参数可以是&amp; str,char或适当的闭包/函数。指定的类型必须实现FromStr特征。

请注意,我快速将它们放在一起,所以它没有经过彻底测试。

答案 1 :(得分:9)

你可以使用text_io crate进行类似scanf的输入,模仿语法中的print!

#[macro_use] extern crate text_io;

fn main() {
    // note that the whitespace between the {} is relevant
    // placing any characters there will ignore them but require
    // the input to have them
    let (s, i, j): (String, i32, f32);
    scan!("{} {} {}\n", s, i, j);
}

您还可以将其分为3个命令:

#[macro_use] extern crate text_io;

fn main() {
    let a: String = read!("{} ");
    let b: i32 = read!("{} ");
    let c: f32 = read!("{}\n");
}

答案 2 :(得分:2)

scan_fmt板条箱提供了另一种选择。它支持简单的模式,在选项中返回其输出,并且具有我认为比text_io更好的语法:

#[macro_use] extern crate scan_fmt;

fn main() {
    let (s, i, j) = scan_fmt!("abce 2 2.5", "{} {d} {f}\n", String, i32, f32);
    println!("{} {} {}", s.unwrap(), i.unwrap(), j.unwrap());
}

答案 3 :(得分:1)

除非出于某种原因需要复制scanf解析事物的确切方法,否则我认为在大多数情况下(以及在大多数语言中),最佳答案是“仅使用regex ”。这是Rust示例:

use regex::Regex;
use std::io::prelude::*;

fn parse_line(s: &str) -> Option<(String, i32, f32)> {
    let r = Regex::new(r"(\w+) (-?\d+) (-?[0-9]*.?[0-9]*)").unwrap();
    let caps = r.captures(s)?;
    let a = caps.get(1)?.as_str().to_string();
    let b = caps.get(2)?.as_str().parse().ok()?;
    let c = caps.get(3)?.as_str().parse().ok()?;
    Some((a, b, c))
}

fn main() {
    let stdin = std::io::stdin();
    let stdin = stdin.lock();
    for line in stdin.lines() {
        println!("{:?}", parse_line(&line.unwrap()));
    }
}

使用正则表达式确实引起了一些直接的问题,尤其是在浮点解析方面。您要支持负数吗?没有数字的小数点有效的浮点数吗?允许使用指数表示法吗?在一个肮脏的数据解析器中,您可能只支持数据在做什么。在实际的应用程序中,此解析器决定可能会成为您应用程序的重要API详细信息,因此一开始要保守一点。