使用 Boost find_last 查找任何
Using Boost find_last to find any of
这是一个 returns 指向 C 字符串路径中文件名部分的指针的函数。
StringT
应该是 char*
或 wchar_t*
.
template <typename StringT>
StringT GetFilenamePos(StringT path) {
typedef boost::iterator_range<typename boost::range_iterator<StringT>::type> StringItRange;
StringItRange lastFound = boost::find_last(path, L"\");
StringT filename = lastFound.empty()
? path
: lastFound.end();
return filename;
}
我不仅想搜索 \
,还想搜索 /
,有没有一种方法可以用 Boost 构造一个查找器对象,在一次字符串遍历中执行此操作(如 find_any_of
)?
我想在一次搜索遍历中完成此操作,而不进行任何复制。
第二点,不太重要;有没有办法更改 L"\"
文字,以便根据模板参数选择宽文字或普通文字?
更新 2 正如帕斯卡曾经说过的:
"I have made this letter longer than usual, because I lack the time to make it short"
我终于找到时间把它缩短了!现在,它不再需要提升:
3。使用 std::string::find_last_of
你可以直接使用它。它本质上是一个单行线 - 除了需要以字符类型独立的方式指定分隔符集。
在这个例子中,我选择使用 boost::string_ref
到 return 对输入字符串的子范围的用户友好的 const 引用。
请注意,使用 boost::string_ref
是可选的,不需要 link 依赖项。如果您愿意,可以将其更改为 std::pair<iterator, iterator>
:
#include <string>
#include <boost/utility/string_ref.hpp>
template <typename StringT, typename C = typename StringT::value_type>
boost::basic_string_ref<C> GetFilename(StringT const& path) {
static const C separators[4] = { '\', '/', ':', 0 };
return boost::basic_string_ref<C>(path).substr(path.find_last_of(separators) + 1);
}
#include <iostream>
int main() {
for (std::string fname : {
"/tmp/somedir/../other//./beautiful filenames.txt.0",
"simple.txt",
"",
})
{
std::cout << "'" << fname << "' -> '" << GetFilename(fname) << "'\n";
}
for (std::wstring fname : {
L"D:\Program Files (64)\Something Else Entirely\but works.just-the-same.exe",
L"\UNCNAME\Something Else Entirely\network.dat",
L"D://testing/test123",
L"http://user:password@hostname:port/test123/resource?query=parameter#yo"
L"E:beautiful filenames.txt.0",
L"simple.txt",
L"",
})
{
std::wcout << "'" << fname << "' -> '" << GetFilename(fname) << "'\n";
}
}
版画
'/tmp/somedir/../other//./beautiful filenames.txt.0' -> 'beautiful filenames.txt.0'
'simple.txt' -> 'simple.txt'
'' -> ''
'D:\Program Files (64)\Something Else Entirely\but works.just-the-same.exe' -> 'but works.just-the-same.exe'
'\UNCNAME\Something Else Entirely\network.dat' -> 'network.dat'
'D://testing/test123' -> 'test123'
'http://user:password@hostname:port/test123/resource?query=parameter#yo' -> 'resource?query=parameter#yo'
'E:beautiful filenames.txt.0' -> 'beautiful filenames.txt.0'
'simple.txt' -> 'simple.txt'
'' -> ''
UPDATE 因为你想要无复制行为,这里有一个使用 Boost Regex
的版本
2。使用升压正则表达式
这个解决方案也是 return 一个 string_ref
适当的字符类型。
事实证明这种方法比要求的要笨得多,但您可能仍然希望 see/use 它用于不那么琐碎的任务。
#include <boost/regex.hpp>
#include <boost/utility/string_ref.hpp>
template <typename StringT, typename C = typename StringT::value_type>
boost::basic_string_ref<C> GetFilename(StringT const& path) {
// it's quite tricky to initialze the pattern generically:
static auto re = [] {
char const pattern[] = "[^\\/:]*$";
std::basic_string<C> spattern(pattern, pattern + sizeof(pattern)-1);
return boost::basic_regex<C>(spattern, boost::regex_constants::optimize);
}();
// the rest is plain sailing:
boost::match_results<typename StringT::const_iterator> mr;
if (boost::regex_search(path.begin(), path.end(), mr, re) && mr[0].matched)
return { &*(mr[0].first), size_t(mr[0].length()) };
return path;
}
#include <iostream>
int main() {
std::string fname = "/tmp/somedir/../other//./beautiful filenames.txt.0";
std::cout << GetFilename(fname) << "\n";
std::wstring wname = L"D:\Program Files (64)\Something Else Entirely\but works.just-the-same.exe";
std::wcout << GetFilename(wname) << "\n";
}
打印:
beautiful filenames.txt.0
but works.just-the-same.exe
1。使用 Boost 文件系统
旧的答案是:这似乎是 Boost 文件系统的工作。
#include <boost/filesystem.hpp>
#include <iostream>
namespace fs = boost::filesystem;
template <typename StringT>
StringT GetFilename(StringT const& path) {
return fs::path(path).filename().string<StringT>();
}
int main() {
#ifndef _WIN32
std::string fname = "/tmp/somedir/../other//./beautiful filenames.txt.0";
std::cout << GetFilename(fname) << "\n";
#else
std::wstring wname = L"D:\Program Files (64)\Something Else Entirely\but works.just-the-same.exe";
std::wcout << GetFilename(wname) << "\n";
#endif
}
这应该打印
beautiful filenames.txt.0
或
but works.just-the-same.exe
取决于您的平台
这是一个 returns 指向 C 字符串路径中文件名部分的指针的函数。
StringT
应该是 char*
或 wchar_t*
.
template <typename StringT>
StringT GetFilenamePos(StringT path) {
typedef boost::iterator_range<typename boost::range_iterator<StringT>::type> StringItRange;
StringItRange lastFound = boost::find_last(path, L"\");
StringT filename = lastFound.empty()
? path
: lastFound.end();
return filename;
}
我不仅想搜索 \
,还想搜索 /
,有没有一种方法可以用 Boost 构造一个查找器对象,在一次字符串遍历中执行此操作(如 find_any_of
)?
我想在一次搜索遍历中完成此操作,而不进行任何复制。
第二点,不太重要;有没有办法更改 L"\"
文字,以便根据模板参数选择宽文字或普通文字?
更新 2 正如帕斯卡曾经说过的:
"I have made this letter longer than usual, because I lack the time to make it short"
我终于找到时间把它缩短了!现在,它不再需要提升:
3。使用 std::string::find_last_of
你可以直接使用它。它本质上是一个单行线 - 除了需要以字符类型独立的方式指定分隔符集。
在这个例子中,我选择使用 boost::string_ref
到 return 对输入字符串的子范围的用户友好的 const 引用。
请注意,使用 boost::string_ref
是可选的,不需要 link 依赖项。如果您愿意,可以将其更改为 std::pair<iterator, iterator>
:
#include <string>
#include <boost/utility/string_ref.hpp>
template <typename StringT, typename C = typename StringT::value_type>
boost::basic_string_ref<C> GetFilename(StringT const& path) {
static const C separators[4] = { '\', '/', ':', 0 };
return boost::basic_string_ref<C>(path).substr(path.find_last_of(separators) + 1);
}
#include <iostream>
int main() {
for (std::string fname : {
"/tmp/somedir/../other//./beautiful filenames.txt.0",
"simple.txt",
"",
})
{
std::cout << "'" << fname << "' -> '" << GetFilename(fname) << "'\n";
}
for (std::wstring fname : {
L"D:\Program Files (64)\Something Else Entirely\but works.just-the-same.exe",
L"\UNCNAME\Something Else Entirely\network.dat",
L"D://testing/test123",
L"http://user:password@hostname:port/test123/resource?query=parameter#yo"
L"E:beautiful filenames.txt.0",
L"simple.txt",
L"",
})
{
std::wcout << "'" << fname << "' -> '" << GetFilename(fname) << "'\n";
}
}
版画
'/tmp/somedir/../other//./beautiful filenames.txt.0' -> 'beautiful filenames.txt.0'
'simple.txt' -> 'simple.txt'
'' -> ''
'D:\Program Files (64)\Something Else Entirely\but works.just-the-same.exe' -> 'but works.just-the-same.exe'
'\UNCNAME\Something Else Entirely\network.dat' -> 'network.dat'
'D://testing/test123' -> 'test123'
'http://user:password@hostname:port/test123/resource?query=parameter#yo' -> 'resource?query=parameter#yo'
'E:beautiful filenames.txt.0' -> 'beautiful filenames.txt.0'
'simple.txt' -> 'simple.txt'
'' -> ''
UPDATE 因为你想要无复制行为,这里有一个使用 Boost Regex
的版本2。使用升压正则表达式
这个解决方案也是 return 一个 string_ref
适当的字符类型。
事实证明这种方法比要求的要笨得多,但您可能仍然希望 see/use 它用于不那么琐碎的任务。
#include <boost/regex.hpp>
#include <boost/utility/string_ref.hpp>
template <typename StringT, typename C = typename StringT::value_type>
boost::basic_string_ref<C> GetFilename(StringT const& path) {
// it's quite tricky to initialze the pattern generically:
static auto re = [] {
char const pattern[] = "[^\\/:]*$";
std::basic_string<C> spattern(pattern, pattern + sizeof(pattern)-1);
return boost::basic_regex<C>(spattern, boost::regex_constants::optimize);
}();
// the rest is plain sailing:
boost::match_results<typename StringT::const_iterator> mr;
if (boost::regex_search(path.begin(), path.end(), mr, re) && mr[0].matched)
return { &*(mr[0].first), size_t(mr[0].length()) };
return path;
}
#include <iostream>
int main() {
std::string fname = "/tmp/somedir/../other//./beautiful filenames.txt.0";
std::cout << GetFilename(fname) << "\n";
std::wstring wname = L"D:\Program Files (64)\Something Else Entirely\but works.just-the-same.exe";
std::wcout << GetFilename(wname) << "\n";
}
打印:
beautiful filenames.txt.0
but works.just-the-same.exe
1。使用 Boost 文件系统
旧的答案是:这似乎是 Boost 文件系统的工作。
#include <boost/filesystem.hpp>
#include <iostream>
namespace fs = boost::filesystem;
template <typename StringT>
StringT GetFilename(StringT const& path) {
return fs::path(path).filename().string<StringT>();
}
int main() {
#ifndef _WIN32
std::string fname = "/tmp/somedir/../other//./beautiful filenames.txt.0";
std::cout << GetFilename(fname) << "\n";
#else
std::wstring wname = L"D:\Program Files (64)\Something Else Entirely\but works.just-the-same.exe";
std::wcout << GetFilename(wname) << "\n";
#endif
}
这应该打印
beautiful filenames.txt.0
或
but works.just-the-same.exe
取决于您的平台