Path 给定两条绝对路径,如何表示其中一条路径相对于另一条路径?

Path 给定两条绝对路径,如何表示其中一条路径相对于另一条路径?,path,rust,Path,Rust,我认为这应该是可行的,因为有一个很好的函数可以规范化路径(因此我可以从规范化我的两个输入路径开始),并且Path和PathBuf为我们提供了一种迭代路径部分的方法。我想这里可以计算出一个公共前缀,然后将锚路径中保留的组件预先添加到初始输入路径的剩余部分 我的问题似乎很普遍: 如果一条路径是另一条路径的基础,则可以使用,但它不会为您计算。/(而是返回一个错误): strip\u prefix的前一个版本是中的path\u relative\u,用于添加。/,但是: 将结果连接到第一条路径的当前

我认为这应该是可行的,因为有一个很好的函数可以规范化路径(因此我可以从规范化我的两个输入路径开始),并且
Path
PathBuf
为我们提供了一种迭代路径部分的方法。我想这里可以计算出一个公共前缀,然后将锚路径中保留的组件预先添加到初始输入路径的剩余部分

我的问题似乎很普遍:


  • 如果一条路径是另一条路径的基础,则可以使用,但它不会为您计算
    。/
    (而是返回一个错误):

    strip\u prefix
    的前一个版本是中的
    path\u relative\u,用于添加
    。/
    ,但是:

  • 将结果连接到第一条路径的当前行为明确表示第二条路径所做的事情相同,即使存在符号链接(这基本上意味着
    base
    需要是
    self
    的前缀)
  • 旧的行为,结果可以从
    。/
    组件开始。符号链接意味着遍历
    base
    路径,然后遍历返回的相对路径可能不会像遍历
    self
    路径那样将您置于同一目录中。但是,如果您使用的是不关心符号链接的基于路径的系统,或者您已经解析了正在使用的路径中的符号链接,则此操作非常有用
  • 如果需要
    。/
    行为,可以从(编译器后端)复制实现。我还没有在板条箱上找到任何提供这个的包裹

    // This routine is adapted from the *old* Path's `path_relative_from`
    // function, which works differently from the new `relative_from` function.
    // In particular, this handles the case on unix where both paths are
    // absolute but with only the root as the common directory.
    fn path_relative_from(path: &Path, base: &Path) -> Option<PathBuf> {
        use std::path::Component;
    
        if path.is_absolute() != base.is_absolute() {
            if path.is_absolute() {
                Some(PathBuf::from(path))
            } else {
                None
            }
        } else {
            let mut ita = path.components();
            let mut itb = base.components();
            let mut comps: Vec<Component> = vec![];
            loop {
                match (ita.next(), itb.next()) {
                    (None, None) => break,
                    (Some(a), None) => {
                        comps.push(a);
                        comps.extend(ita.by_ref());
                        break;
                    }
                    (None, _) => comps.push(Component::ParentDir),
                    (Some(a), Some(b)) if comps.is_empty() && a == b => (),
                    (Some(a), Some(b)) if b == Component::CurDir => comps.push(a),
                    (Some(_), Some(b)) if b == Component::ParentDir => return None,
                    (Some(a), Some(_)) => {
                        comps.push(Component::ParentDir);
                        for _ in itb {
                            comps.push(Component::ParentDir);
                        }
                        comps.push(a);
                        comps.extend(ita.by_ref());
                        break;
                    }
                }
            }
            Some(comps.iter().map(|c| c.as_os_str()).collect())
        }
    }
    
    //此例程改编自*old*路径的'Path\u relative\u from'`
    //函数,其工作方式与新的“relative_from”函数不同。
    //特别是,这在unix上处理了两条路径都相同的情况
    //绝对,但只有根目录作为公共目录。
    fn路径\相对\来自(路径:&路径,基:&路径)->选项{
    使用std::path::Component;
    如果path.is_absolute()!=base.is_absolute(){
    如果path.is_绝对(){
    Some(路径buf::from(路径))
    }否则{
    没有一个
    }
    }否则{
    让mut ita=path.components();
    让mut-itb=base.components();
    让mut comps:Vec=Vec![];
    环路{
    匹配(ita.next(),itb.next()){
    (无,无)=>中断,
    (部分(a),无)=>{
    补偿推力(a);
    公司扩展(ita.by_ref());
    打破
    }
    (无,)=>comps.push(组件::ParentDir),
    (一些(a),一些(b))如果comps.为空(&&a==b=>(),
    (一些(a),一些(b))如果b==Component::CurDir=>comps.push(a),
    如果b==Component::ParentDir=>返回None,
    (一些(a),一些())=>{
    comps.push(组件::ParentDir);
    投标人须知中的uu{
    comps.push(组件::ParentDir);
    }
    补偿推力(a);
    公司扩展(ita.by_ref());
    打破
    }
    }
    }
    一些(comps.iter().map(| c | c.as_os_str()).collect())
    }
    }
    
    如果一条路径是另一条路径的基础,您可以使用,但它不会为您计算
    。/
    (而是返回一个错误):

    strip\u prefix
    的前一个版本是
    中的
    path\u relative\u,用于添加
    。/
    ,但是:

  • 将结果连接到第一条路径的当前行为明确表示第二条路径所做的事情相同,即使存在符号链接(这基本上意味着
    base
    需要是
    self
    的前缀)
  • 旧的行为,结果可以从
    。/
    组件开始。符号链接意味着遍历
    base
    路径,然后遍历返回的相对路径可能不会像遍历
    self
    路径那样将您置于同一目录中。但是,如果您使用的是不关心符号链接的基于路径的系统,或者您已经解析了正在使用的路径中的符号链接,则此操作非常有用
  • 如果需要
    。/
    行为,可以从(编译器后端)复制实现。我还没有在板条箱上找到任何提供这个的包裹

    // This routine is adapted from the *old* Path's `path_relative_from`
    // function, which works differently from the new `relative_from` function.
    // In particular, this handles the case on unix where both paths are
    // absolute but with only the root as the common directory.
    fn path_relative_from(path: &Path, base: &Path) -> Option<PathBuf> {
        use std::path::Component;
    
        if path.is_absolute() != base.is_absolute() {
            if path.is_absolute() {
                Some(PathBuf::from(path))
            } else {
                None
            }
        } else {
            let mut ita = path.components();
            let mut itb = base.components();
            let mut comps: Vec<Component> = vec![];
            loop {
                match (ita.next(), itb.next()) {
                    (None, None) => break,
                    (Some(a), None) => {
                        comps.push(a);
                        comps.extend(ita.by_ref());
                        break;
                    }
                    (None, _) => comps.push(Component::ParentDir),
                    (Some(a), Some(b)) if comps.is_empty() && a == b => (),
                    (Some(a), Some(b)) if b == Component::CurDir => comps.push(a),
                    (Some(_), Some(b)) if b == Component::ParentDir => return None,
                    (Some(a), Some(_)) => {
                        comps.push(Component::ParentDir);
                        for _ in itb {
                            comps.push(Component::ParentDir);
                        }
                        comps.push(a);
                        comps.extend(ita.by_ref());
                        break;
                    }
                }
            }
            Some(comps.iter().map(|c| c.as_os_str()).collect())
        }
    }
    
    //此例程改编自*old*路径的'Path\u relative\u from'`
    //函数,其工作方式与新的“relative_from”函数不同。
    //特别是,这在unix上处理了两条路径都相同的情况
    //绝对,但只有根目录作为公共目录。
    fn路径\相对\来自(路径:&路径,基:&路径)->选项{
    使用std::path::Component;
    如果path.is_absolute()!=base.is_absolute(){
    如果path.is_绝对(){
    Some(路径buf::from(路径))
    }否则{
    没有一个
    }
    }否则{
    让mut ita=path.components();
    让mut-itb=base.components();
    让mut comps:Vec=Vec![];
    环路{
    匹配(ita.next(),itb.next()){
    (无,无)=>中断,
    (部分(a),无)=>{
    补偿推力(a);
    公司扩展(ita.by_ref());
    打破
    }
    (无,)=>comps.push(组件::ParentDir),
    (一些(a),一些(b))如果comps.为空(&&a==b=>(),
    (一些(a),一些(b))如果b==Component::CurDir=>comps.push(a),
    如果b==Component::ParentDir=>返回None,
    (一些(a),一些())=>{
    comps.push(组件::ParentDir);
    投标人须知中的uu{
    组件推送(组件::ParentDir
    
    extern crate pathdiff;
    
    pathdiff::diff_paths(path, base);