2017-07-25 179 views
2

我想从给定的String路径中提取文件的扩展名。从Rust中给定路径中提取文件扩展名惯用

下面这段代码工作,但我不知道是否有一个更清洁,更地道的防锈方法来实现这一目标:

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"); 

} 
+0

所以你想要得到最左边的点后的一切?这会给错误的结果“版本1.2.txt” – interjay

+0

@interjay,是的,因此我维护允许扩展的散列表,因此'2.txt'会惊慌。我的意图是以通用的方式提取可能的扩展,并与允许的扩展hashmap进行比较。 – Sokio

+2

'.tar.gz'不是一个独立的扩展名,它是一个'.gz'文件,当解压缩时会得到一个'.tar'文件。你应该遵循相同的过程。提取扩展部分和非扩展部分,并递归处理非扩展部分拉伸扩展。 – loganfsmyth

回答

4

在惯用的锈可以失败应该是一个OptionResult函数的返回类型。一般来说,函数还应该接受切片而不是String,并且只在必要时创建新的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")); 

使用and_then是方便在这里,因为这意味着你没有解开的extension()和处理返回的Option<&OsStr>在致电to_str之前可能有None。我也可以使用lambda |s| s.to_str()而不是OsStr::to_str - 这可能是一个偏好或意见问题,哪个更加习惯。

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

1

什么比用更地道锈病的builtin method呢?

Path::new(&filename).extension() 
+0

感谢您的快速响应,但我认为这个例子会失败: 'assert_eq!(get_extension_from_filename(“abc.tar.gz”.to_string()),“tar.gz”);' – Sokio

+0

@Sokio哦,我错过了那。 – Alexander

相关问题