我可以使用 `std::path::Path` 的 `strip_prefix` 来替换动态前缀吗?

max*_*man 1 path rust

我有兴趣这样做的原因是因为我的路径中有一部分将保持不变,但我希望将其与其所有父部分一起删除。

所以如果我们说,

some/unknown/path/foo/bar/baz
Run Code Online (Sandbox Code Playgroud)

我想回来

bar/baz
Run Code Online (Sandbox Code Playgroud)

但我期望我只知道foo/...直接进行我关心的道路的一部分。

也许strip_prefix是错误的方法,所以如果有更好的方法可以做到这一点,我当然会很感激您指出这个方向。

tre*_*tcl 7

strip_prefix不会做你想做的事,因为它要求你知道要剥离的前缀。但是,您可以使用iter获取路径组件上的迭代器,然后使用标准方法仅从您想要的部分Iterator构建新的。PathBuf

这是一个例子(尝试一下):

let p = path::Path::new("some/unknown/path/foo/bar/baz");
let q: path::PathBuf = p.iter()   // iterate over path components
    .skip_while(|s| *s != "foo")  // skip everything before "foo"
    .skip(1)                      // skip "foo" itself
    .collect();                   // collect the rest into a PathBuf
println!("{:?}", q); // prints "bar/baz"
Run Code Online (Sandbox Code Playgroud)

(这将分配一个新的PathBuf.Shepmaster的答案显示了如何&Path在不分配的情况下获得对原始文件的引用。)

然后,您可以使用to_str、、to_string_lossyinto_os_string加号OsString::into_string来获取可以转换为 的内容String

另请参阅:如何将 PathBuf 转换为 String


She*_*ter 5

虽然我认为trentcl 的答案更清晰,但值得展示一些非分配版本。

使用Path::strip_prefix

要使用Path::strip_prefix,您需要知道前缀。parent我们可以通过沿着原始路径向上走直到找到“foo”来生成它ends_with

use std::path::Path;

fn thing1<P>(path: &P) -> Result<&Path, ()>
where
    P: AsRef<Path> + ?Sized,
{
    let original = path.as_ref();
    let mut prefix = original;

    while !prefix.ends_with("foo") {
        prefix = match prefix.parent() {
            Some(p) => p,
            None => return Err(()),
        };
    }

    original.strip_prefix(prefix).map_err(|_| ())
}

fn main() {
    let x = thing1("some/unknown/path/foo/bar/baz");
    println!("{:?}", x);
}
Run Code Online (Sandbox Code Playgroud)

用迭代器

我们可以迭代路径的各个部分,在它不是“foo”时获取值。一旦我们将迭代器推进得足够远,我们就可以获得余数作为路径

use std::path::Path;

fn thing2<P>(path: &P) -> &Path
where
    P: AsRef<Path> + ?Sized,
{
    let path = path.as_ref();
    let mut i = path.iter();

    for _ in i.by_ref().take_while(|c| *c != "foo") {}

    i.as_path()
}

fn main() {
    let x = thing2("some/unknown/path/foo/bar/baz");
    println!("{:?}", x);
}
Run Code Online (Sandbox Code Playgroud)

当“foo”不存在时,这将返回一个空路径。