The task is fairly simple as the base filename is just the part of the string starting at the last delimeter for folders:
std::string base_filename = path.substr(path.find_last_of("/") + 1)
If the extension is to be removed as well the only thing to do is find the last .
and take a substr
to this point
std::string::size_type const p(base_filename.find_last_of('.'));
std::string file_without_extension = base_filename.substr(0, p);
Perhaps there should be a check to cope with files solely consisting of extensions (ie .bashrc
...)
If you split this up into seperate functions you're flexible to reuse the single tasks:
template<class T>
T base_name(T const & path, T const & delims = "/")
{
return path.substr(path.find_last_of(delims) + 1);
}
template<class T>
T remove_extension(T const & filename)
{
typename T::size_type const p(filename.find_last_of('.'));
return p > 0 && p != T::npos ? filename.substr(0, p) : filename;
}
The code is templated to be able to use it with different std::basic_string
instances (i.e. std::string
& std::wstring
...)
The downside of the templation is the requirement to specify the template parameter if a const char *
is passed to the functions.
So you could either:
A) Use only std::string
instead of templating the code
std::string base_name(std::string const & path)
{
return path.substr(path.find_last_of("/") + 1);
}
B) Provide wrapping function using std::string
(as intermediates which will likely be inlined / optimized away)
inline std::string string_base_name(std::string const & path)
{
return base_name(path);
}
C) Specify the template parameter when calling with const char *
.
std::string base = base_name<std::string>("some/path/file.ext");
Result
std::string filepath = "C:\MyDirectory\MyFile.bat";
std::cout << remove_extension(base_name(filepath)) << std::endl;
Prints
MyFile
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…