将字符串解析为整数

3

我正在尝试在字符串中查找模式并将其转换为整数。

首先,我要寻找一个字符串:

let haystack = "HTTP/1.1 200\r\n";
let needle = "HTTP/1.";

let http_location = haystack.rfind(needle);
if (http_location.is_some()) {

现在我找到了它,我可以想到两种获取数字状态的方法。要么:

    let mut temp_str = haystack.char_at(http_location.unwrap());
    let status = String::from_str(temp_str);
}

或者:

    let status = String::from_str(&haystack[http_location.unwrap()]);
}

很遗憾,它们都已被弃用(而且可能是错误的)。目前正确的做法是什么?

此外,这部分的样式是否正确?

let http_location = haystack.rfind(needle);
if (http_location.is_some())
1个回答

5

解析是一个广泛而多样化的主题。有简单易用的解析工具,也有高性能的解析工具以及介于两者之间的一系列工具。

fn main() {
    let haystack = "HTTP/1.1 200\r\n";
    let needle = "HTTP/1.";

    let z: Option<u8> = haystack.rfind(needle).and_then(|pt| {
        let after_match = &haystack[(pt + needle.len())..];
        after_match.splitn(2, " ").next()
    }).and_then(|val| {
        val.parse().ok()
    });

    println!("{:?}", z)
}

在这里,我们使用 rfind,就像之前一样,但有可能失败。我们使用 and_then 来运行闭包,如果结果为 Some。第一个闭包在找到匹配字符串后切割该字符串,并在空格上以2个部分为最大值进行分割。这可能会失败,所以我们使用第二个 and_then 来使用 parse,它也可能会以 Result 失败,因此我们将其转换为 Option 以保留类型。

在最后,我们仍然可能失败,因为我们解析的内容可能不是可解析的数字!

Rust 真的帮助您明确可以失败的位置,并且您必须处理它们。 ^_^

在这种情况下:

  1. 字符串中可能没有 "HTTP/1."
  2. 迭代器必须在某些点结束,因此它们可以返回 None
  3. 将字符串解析为数字可能失败。

以下是使用正则表达式包的另一种解决方案:

extern crate regex;

use regex::Regex;

fn main() {
    let haystack = "HTTP/1.1 200\r\n";

    let re = Regex::new(r"HTTP/1.(\d) (\d+)\r\n").unwrap();
    let captures = re.captures(haystack).unwrap();
    let version: Option<u8> = captures.at(1).and_then(|version| version.parse().ok());
    let status: Option<u8> = captures.at(2).and_then(|version| version.parse().ok());

    assert_eq!(Some(1), version);
    assert_eq!(Some(200), status);

    println!("Version: {:?}, Status: {:?}", version, status);
}

你会发现我们有相同的故障模式,但结构略有不同。

或者可能是使用 Resulttry! 的版本:

#[derive(Debug,Copy,Clone,PartialEq)]
enum Error {
    StartNotFound,
    NotANumber,
}

fn parse_it(haystack: &str) -> Result<u8, Error> {
    let needle = "HTTP/1.";
    let pt = try!(haystack.rfind(needle).ok_or(Error::StartNotFound));
    let after_match = &haystack[(pt + needle.len())..];
    let val = after_match.splitn(2, " ").next().unwrap();
    val.parse().map_err(|_| Error::NotANumber)
}

fn main() {
    println!("{:?}", parse_it("HTTP/1.1 200\r\n"));
    println!("{:?}", parse_it("HTTP/1"));
    println!("{:?}", parse_it("HTTP/1.cow"));
}

这是 Rust 在“生产”中应该编写的方式吗?它看起来非常简洁,似乎是一些时间离开代码后难以理解的东西。无论如何,你能解释一下“.and_then()”的功能和语法吗?我觉得官方文档假定读者具有一些函数式编程的知识,而我并没有。 - andrey
1
@andreyg 我想说,美在观者的眼中!你可以使用更多的match语句重写它,或者从Option升级到Result,然后利用try!宏。我已经添加了这个和一个正则表达式示例。我不能代表整个Rust社区,但你应该编写自己能够理解的代码!“每个人都知道调试比一开始编写程序要难两倍。所以如果你在编写时越聪明,那么你将如何调试呢?”- Brian Kernighan - Shepmaster

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接