首页 > 解决方案 > 解析一个整数,忽略任何非数字后缀

问题描述

我有一个以数字开头的字符串列表。但是,我不知道它们以什么结尾。一些示例可能是"12/1/1""33""17abc"。我想读取每个字符串开头的数字,将示例分别转换为123317

我已经让它与下面的代码一起工作。

"12/1/1".chars().take_while(|c| c.is_numeric()).collect::<String>().parse::<usize>()

但是,我确实觉得存在更有效/更清洁的解决方案。一个没有字符串集合和/或不那么冗长。
我宁愿不使用任何外部板条箱。

标签: rust

解决方案


这取决于您对“更好”的定义。如果您只是想删除不必要的String创建,那么您可以使用atoicrate

或者,您也可以使用nomcrate,并使用digit0()来创建您自己的atoi()函数:

// nom = "6.0"
use nom::character::complete::digit0;
use nom::error::Error;
use std::str::FromStr;

fn atoi<F: FromStr>(input: &str) -> Result<F, <F as FromStr>::Err> {
    digit0::<_, Error<_>>(input).unwrap().1.parse::<F>()
}

fn main() {
    println!("{:?}", atoi::<usize>("12/1/1")); // Prints `Ok(12)`
    println!("{:?}", atoi::<usize>("33"));     // Prints `Ok(33)`
    println!("{:?}", atoi::<usize>("17abc"));  // Prints `Ok(17)`
    println!("{:?}", atoi::<usize>("abc"));    // Prints `Err(ParseIntError { kind: Empty })`
    println!("{:?}", atoi::<usize>(""));       // Prints `Err(ParseIntError { kind: Empty })`
}

是安全的unwrap(),就好像没有数字一样Ok仍然返回,空字符串由parse().


由于您不想使用任何外部 crate,因此您可以使用find()来获取第一个非数字字符的索引。

请注意,@AlexLarionov 的答案在溢出时会出现恐慌,而这个则不会。

use std::str::FromStr;

fn atoi<F: FromStr>(input: &str) -> Result<F, <F as FromStr>::Err> {
    let i = input.find(|c: char| !c.is_numeric()).unwrap_or_else(|| input.len());
    input[..i].parse::<F>()
}

fn main() {
    println!("{:?}", atoi::<usize>("12/1/1")); // Prints `Ok(12)`
    println!("{:?}", atoi::<usize>("33"));     // Prints `Ok(33)`
    println!("{:?}", atoi::<usize>("17abc"));  // Prints `Ok(17)`
    println!("{:?}", atoi::<usize>("abc"));    // Prints `Err(ParseIntError { kind: Empty })`
    println!("{:?}", atoi::<usize>(""));       // Prints `Err(ParseIntError { kind: Empty })`

    println!("{:?}", atoi::<usize>("123456789101112131415"));
    // Prints `Err(ParseIntError { kind: PosOverflow })`
}

推荐阅读