patternrustModerate
Extracting the last component (basename) of a filesystem path
Viewed 0 times
lastthepathfilesystemextractingbasenamecomponent
Problem
fn basename(path: &'a str, sep: char) -> Cow {
let pieces = path.split(sep);
match pieces.last() {
Some(p) => p.into(),
None => path.into(),
}
}Usage:
println!("'{}'", basename("foo", '/')); // outputs 'foo'
println!("'{}'", basename("bob/", '/')); // outputs ''
println!("'{}'", basename("/usr/local/bin/rustc", '/')); // outputs 'rustc'I think the
split() into a match on last() is kind of elegant.I know there is some work needed to handle both
str and String, I am not sold on the use of Cow and needing to define a lifetime for the string.I am not sold on
Cow because later on I need to extract from it.let prog = basename(&args[0], '/').into_owned();It feels like I am working too hard.
Solution
Firstly, you should use
Secondly, you shouldn’t be using strings for this; you should be using paths, because that’s semantically what you’re dealing with.
The easiest way to get a path tends to be to take a
You can get the base name from a
Anyway, the point of this latter part is just that for something that is semantically a path, you should be handling it specially, as a rule; a path need not be Unicode. Think on it more.
rsplit and next rather than split and last, as it starts at the more appropriate end:fn basename(path: &'a str, sep: char) -> Cow {
let pieces = path.rsplit(sep);
match pieces.next() {
Some(p) => p.into(),
None => path.into(),
}
}Secondly, you shouldn’t be using strings for this; you should be using paths, because that’s semantically what you’re dealing with.
The easiest way to get a path tends to be to take a
&Path or a generic parameter implementing AsRef and calling .as_ref() on it; str, String, Path, PathBuf and more implement it.You can get the base name from a
&Path with file_name; this admittedly produces a Option, so if you want to display the path you’d need to convert it back towards a string with e.g. .and_then(|s| s.to_str()).Anyway, the point of this latter part is just that for something that is semantically a path, you should be handling it specially, as a rule; a path need not be Unicode. Think on it more.
Code Snippets
fn basename<'a>(path: &'a str, sep: char) -> Cow<'a, str> {
let pieces = path.rsplit(sep);
match pieces.next() {
Some(p) => p.into(),
None => path.into(),
}
}Context
StackExchange Code Review Q#98536, answer score: 12
Revisions (0)
No revisions yet.