从Rust中给定路径中提取文件扩展名惯用
问题描述:
我想从给定的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");
}
答
在惯用的锈可以失败应该是一个Option
或Result
函数的返回类型。一般来说,函数还应该接受切片而不是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.2.txt” – interjay
@interjay,是的,因此我维护允许扩展的散列表,因此'2.txt'会惊慌。我的意图是以通用的方式提取可能的扩展,并与允许的扩展hashmap进行比较。 – Sokio
'.tar.gz'不是一个独立的扩展名,它是一个'.gz'文件,当解压缩时会得到一个'.tar'文件。你应该遵循相同的过程。提取扩展部分和非扩展部分,并递归处理非扩展部分拉伸扩展。 – loganfsmyth