String 锈菌有类似scanf的东西吗?

String 锈菌有类似scanf的东西吗?,string,parsing,rust,String,Parsing,Rust,我需要在每一行上解析一个文件 <string><space><int><space><float> 在C中,我会: scanf("%s%d%f", &s, &i, &f); 如何在Rust中轻松且惯用地执行此操作?您可以将板条箱用于模拟打印的类似scanf的输入宏 #[macro_use] extern crate text_io; fn main() { // note that the whit

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

<string><space><int><space><float>
在C中,我会:

scanf("%s%d%f", &s, &i, &f);
如何在Rust中轻松且惯用地执行此操作?

您可以将板条箱用于模拟
打印的类似scanf的输入

#[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");
}

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

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"))
}
macro\u规则!扫描{
($string:expr,$sep:expr,$($x:ty),+)=>{{
让mut iter=$string.split($sep);
($(iter.next()和_then(| word | word.parse::().ok(),)*)
}}
}
fn main(){
让输出=扫描!(“2个假福克斯”,字符::是空白,u8,布尔,字符串);
println!(“{:?}”,输出);/(一些(2),一些(假),一些(“福克斯”))
}
宏的第二个输入参数可以是&str、char或适当的闭包/函数。指定的类型必须实现FromStr特性

请注意,我很快就把它放在了一起,所以它还没有经过彻底的测试

板条箱提供了另一种选择。它支持简单的模式,以选项的形式返回其输出,并且有一种我觉得更好的语法:


除非出于某种原因需要复制
scanf
解析事物的确切方式,否则我认为在大多数情况下(以及在大多数语言中)最好的答案是“只使用
regex
”,下面是一个例子:

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()));
    }
}
使用regex::regex;
使用std::io::prelude::*;
fn parse_行(s:&str)->选项{
设r=Regex::new(r“(\w+)(?\d+)(?[0-9].?[0-9]*)”).unwrap();
设caps=r.caps?;
设a=caps.get(1)?.as_str()to_string();
设b=caps.get(2)?.as_str().parse().ok()?;
设c=caps.get(3)?.as_str().parse().ok()?;
一些((a、b、c))
}
fn main(){
设stdin=std::io::stdin();
设stdin=stdin.lock();
对于标准中的行。行(){
println!(“{:?}”,parse_行(&line.unwrap());
}
}
使用正则表达式确实会引起一些直接的问题,特别是在浮点解析方面。是否要支持负数?没有数字的小数点是有效的浮点吗?允许指数记数法吗?在一个快速而肮脏的数据解析器中,您可能只支持您的数据正在做的任何事情。在实际应用程序中,这个解析器决策可能会成为应用程序的一个重要API细节,因此一开始保守是值得的

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