Path 以惯用方式从给定路径提取文件扩展名

Path 以惯用方式从给定路径提取文件扩展名,path,rust,filenames,file-extension,Path,Rust,Filenames,File Extension,我试图从给定的字符串路径中提取文件的扩展名 下面的代码是有效的,但我想知道是否有一种更干净、更地道的方法来实现这一点: use std::path::Path; fn main() { fn get_extension_from_filename(filename: String) -> String { //Change it to a canonical file path. let path = Path::new(&filena

我试图从给定的字符串路径中提取文件的扩展名

下面的代码是有效的,但我想知道是否有一种更干净、更地道的方法来实现这一点:

use std::path::Path;

fn main() {

    fn get_extension_from_filename(filename: String) -> String {

        //Change it to a canonical file path.
        let path = Path::new(&filename).canonicalize().expect(
            "Expecting an existing filename",
        );

        let filepath = path.to_str();
        let name = filepath.unwrap().split('/');
        let names: Vec<&str> = name.collect();
        let extension = names.last().expect("File extension can not be read.");
        let extens: Vec<&str> = extension.split(".").collect();

        extens[1..(extens.len())].join(".").to_string()
    }

    assert_eq!(get_extension_from_filename("abc.tar.gz".to_string()) ,"tar.gz" );
    assert_eq!(get_extension_from_filename("abc..gz".to_string()) ,".gz" );
    assert_eq!(get_extension_from_filename("abc.gz".to_string()) , "gz");

}
使用std::path::path;
fn main(){
fn从文件名(文件名:String)->String获取扩展名{
//将其更改为规范文件路径。
让path=path::new(&filename).canonicalize().expect(
“应为现有文件名”,
);
让filepath=path.to_str();
让name=filepath.unwrap().split('/');
let name:Vec=name.collect();
让extension=names.last().expect(“无法读取文件扩展名”);
让extens:Vec=extension.split(“.”.collect();
extens[1..(extens.len())].join(“.”)to_string()
}
断言(从文件名(“abc.tar.gz.to_string()),“tar.gz”中获取扩展名);
断言(从文件名(“abc..gz.”到字符串(),“.gz”)获取扩展名);
断言\u eq!(从\u filename(“abc.gz.to_ustring()),“gz”)获取\u扩展名;
}

还有什么比使用Rust更惯用的呢


在习惯用法中,可能失败的函数的返回类型应该是
选项
结果
。通常,函数也应该接受切片而不是
String
s,并且只在必要时创建一个新的
String
。这减少了过多的复制和堆分配

您可以使用提供的
extension()
方法,然后将生成的
OsStr
转换为
&str

use std::path::Path;
use std::ffi::OsStr;

fn get_extension_from_filename(filename: &str) -> Option<&str> {
    Path::new(filename)
        .extension()
        .and_then(OsStr::to_str)
}

assert_eq!(get_extension_from_filename("abc.gz"), Some("gz"));
使用std::path::path;
使用std::ffi::OsStr;
fn从文件名(文件名:&str)->选项获取扩展名{
路径::新建(文件名)
.extension()
.然后(OsStr::to_str)
}
断言!(从文件名(“abc.gz”)中获取扩展名(“gz”);
在这里使用
和_then
很方便,因为这意味着您不必在调用
到_str
之前打开
扩展()返回的
选项
,并处理该选项为
无的可能性。我也可以用lambda
|s.to_str()
来代替
OsStr::to_str
——这可能是一个偏好或观点的问题,哪一个更惯用


请注意,参数
&str
和返回值都是对为断言创建的原始字符串片段的引用。返回的切片无法超过它引用的原始切片,因此如果需要更长时间,您可能需要从此结果创建一个拥有的
字符串。

感谢您的快速响应,但我认为此示例将失败:
assert\u eq!(从文件名(“abc.tar.gz.to_string()),“tar.gz”中获取扩展名)@Sokio哦,我错过了。所以你想在最左边的点之后得到所有东西吗?这将给出错误的结果,例如“Version 1.2.txt”@interjay,是的,因此我维护了允许扩展的hashmap,因此
2.txt
会死机。我的目的是以一种通用的方式提取一个可能的扩展名,并与允许的扩展名hashmap进行比较。
.tar.gz
不是一个独立的扩展名,它是一个
.gz
文件,解压缩后会得到一个
.tar
文件。你应该遵循同样的过程。提取扩展和非扩展部分,并递归地处理从中提取扩展的非扩展部分。
use std::path::Path;
use std::ffi::OsStr;

fn get_extension_from_filename(filename: &str) -> Option<&str> {
    Path::new(filename)
        .extension()
        .and_then(OsStr::to_str)
}

assert_eq!(get_extension_from_filename("abc.gz"), Some("gz"));