使用 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>

Live On Coliru

#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 它用于不那么琐碎的任务。

Live On Coliru

#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 文件系统的工作。

Live On Coliru

#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

取决于您的平台