如何检查字符串是否以.txt结尾

问题描述 投票:0回答:13

我正在学习基本的 C++,现在我从用户那里得到了一个字符串,我想检查他们是否输入了整个文件名(包括 .txt)。我有字符串,但如何检查字符串是否以“.txt”结尾?

string fileName;

cout << "Enter filename: \n";
cin >> fileName;

string txt = fileName.Right(4);

Right(int)
方法仅适用于CString,因此上面的代码不起作用。如果可能的话,我想使用常规字符串。有什么想法吗?

c++ string
13个回答
46
投票

不幸的是这个有用的函数不在标准库中。 写起来很容易。

bool has_suffix(const std::string &str, const std::string &suffix)
{
    return str.size() >= suffix.size() &&
           str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0;
}

14
投票

使用 boost ends_with 谓词:

#include <boost/algorithm/string/predicate.hpp>

if (boost::ends_with(fileName, ".txt")) { /* ... */ }

12
投票

您已经得到了很多答案,但我决定添加另一个:

bool ends_with(std::string const &a, std::string const &b) {
    auto len = b.length();
    auto pos = a.length() - len;
    if (pos < 0)
        return false;
    auto pos_a = &a[pos];
    auto pos_b = &b[0];
    while (*pos_a)
        if (*pos_a++ != *pos_b++)
            return false;
    return true;
}

既然您已经得到了相当多的答案,也许值得进行快速测试和结果总结:

#include <iostream>
#include <string>
#include <vector>
#include <time.h>
#include <iomanip>

bool ends_with(std::string const &a, std::string const &b) {
    auto len = b.length();
    auto pos = a.length() - len;
    if (pos < 0)
        return false;
    auto pos_a = &a[pos];
    auto pos_b = &b[0];
    while (*pos_a)
        if (*pos_a++ != *pos_b++)
            return false;
    return true;
}

bool ends_with_string(std::string const& str, std::string const& what) {
    return what.size() <= str.size()
        && str.find(what, str.size() - what.size()) != str.npos;
}

bool has_suffix(const std::string &str, const std::string &suffix)
{
    return str.size() >= suffix.size() &&
        str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0;
}

bool has_suffix2(const std::string &str, const std::string &suffix)
{
    bool index = str.find(suffix, str.size() - suffix.size());
    return (index != -1);
}

bool isEndsWith(const std::string& pstr, const std::string& substr)
{
    int tlen = pstr.length();
    int slen = substr.length();

    if (slen > tlen)
        return false;

    const char* tdta = pstr.c_str();
    const char* sdta = substr.c_str();

    while (slen)
    {
        if (tdta[tlen] != sdta[slen])
            return false;

        --slen; --tlen;
    }
    return true;
}

bool ends_with_6502(const std::string& str, const std::string& end) {
    size_t slen = str.size(), elen = end.size();
    if (slen <= elen) return false;
    while (elen) {
        if (str[--slen] != end[--elen]) return false;
    }
    return true;
}

bool ends_with_rajenpandit(std::string const &file, std::string const &suffix) {
    int pos = file.find(suffix);
    return (pos != std::string::npos);
}

template <class F>
bool test(std::string const &label, F f) {
    static const std::vector<std::pair<std::string, bool>> tests{
        { "this is some text", false },
        { "name.txt.other", false },
        { "name.txt", true }
    };
    bool result = true;

    std::cout << "Testing: " << std::left << std::setw(20) << label;
    for (auto const &s : tests)
        result &= (f(s.first, ".txt") == s.second);
    if (!result) {
        std::cout << "Failed\n";
        return false;
    }
    clock_t start = clock();
    for (int i = 0; i < 10000000; i++)
        for (auto const &s : tests)
            result &= (f(s.first, ".txt") == s.second);
    clock_t stop = clock();
    std::cout << double(stop - start) / CLOCKS_PER_SEC << " Seconds\n";
    return result;
}

int main() {
    test("Jerry Coffin", ends_with);
    test("Dietrich Epp", has_suffix);
    test("Dietmar", ends_with_string);
    test("Roman", isEndsWith);
    test("6502", ends_with_6502);
    test("rajenpandit", ends_with_rajenpandit);
}

gcc 的结果:

Testing: Jerry Coffin           3.416 Seconds
Testing: Dietrich Epp           3.461 Seconds
Testing: Dietmar                3.695 Seconds
Testing: Roman                  3.333 Seconds
Testing: 6502                   3.304 Seconds
Testing: rajenpandit            Failed

VC++的结果:

Testing: Jerry Coffin           0.718 Seconds
Testing: Dietrich Epp           0.982 Seconds
Testing: Dietmar                1.087 Seconds
Testing: Roman                  0.883 Seconds
Testing: 6502                   0.927 Seconds
Testing: rajenpandit            Failed

是的,它们是在相同的硬件上运行的,是的,我运行了它们很多次,并使用 g++ 尝试了不同的优化选项,看看是否可以让它至少接近匹配 VC++。我不能。我没有立即解释为什么 g++ 会为此测试生成如此糟糕的代码,但我相当有信心它确实如此。


4
投票

使用

std::string::substr

if (filename.substr(std::max(4, filename.size())-4) == std::string(".txt")) {
    // Your code here
}

3
投票

您可以使用另一个字符串来验证扩展名,如下所示:

string fileName;

cout << "Enter filename: \n";
cin >> fileName;

//string txt = fileName.Right(4);
string ext="";
for(int i = fileName.length()-1;i>fileName.length()-5;i--)
{
    ext += fileName[i];
}
cout<<ext;
if(ext != "txt.")
    cout<<"error\n";

检查是否等于

"txt."
因为 i 以文件名的长度开头,所以
ext
以相反的方式填充


3
投票
bool has_suffix(const std::string &str, const std::string &suffix)
{
    std::size_t index = str.find(suffix, str.size() - suffix.size());
    return (index != std::string::npos);
}

2
投票

最简单的方法可能是验证字符串是否足够长以容纳

".txt"
,并查看是否可以在位置
size() - 4
找到字符串,例如:

bool ends_with_string(std::string const& str, std::string const& what) {
    return what.size() <= str.size()
        && str.find(what, str.size() - what.size()) != str.npos;
}

2
投票

不幸的是,标准库中没有这个东西,而且写起来也有点烦人。这是我的尝试:

bool ends_with(const std::string& str, const std::string& end) {
    size_t slen = str.size(), elen = end.size();
    if (slen < elen) return false;
    while (elen) {
        if (str[--slen] != end[--elen]) return false;
    }
    return true;
}

2
投票

除了提到的选项之外,我还能想到两个选项:
1) 正则表达式 - 可能有点过分了,但简单的正则表达式是很好且可读的恕我直言
2)rbegin - 有点好,可能是我错过了一些东西,但它是:

bool ends_with(const string& s, const string& ending)
{
return (s.size()>=ending.size()) && equal(ending.rbegin(), ending.rend(), s.rbegin());
}

http://coliru.stacked-crooked.com/a/4de3eafed3bff6e3


1
投票

这应该可以。

bool ends_with(const std::string & s, const std::string & suffix) {
     return s.rfind(suffix) == s.length() - suffix.length();
}

在此验证


1
投票

自 C++17 起,您可以使用 文件系统库中的 path 类。

#include <filesystem>

bool ends_with_txt(const std::string& fileName) {
    return std::filesystem::path{fileName}.extension() == ".txt";
}

0
投票

这是“完全自写”的解决方案:

bool isEndsWith(const std::string& pstr, const std::string& substr) const
{
    int tlen = pstr.length();
    int slen = substr.length();

    if(slen > tlen)
        return false;

    const char* tdta = pstr.c_str();
    const char* sdta = substr.c_str();

    while(slen)
    {
        if(tdta[tlen] != sdta[slen])
            return false;

        --slen; --tlen;
    }
    return true;
}

0
投票

我实现了:

bool ends_with(std::string const &a, std::string const &b) {
    auto len = b.length();
    auto pos = a.length() - len;
    if (pos < 0)
        return false;
    auto pos_a = &a[pos];
    auto pos_b = &b[0];
    while (*pos_a)
        if (*pos_a++ != *pos_b++)
            return false;
    return true;
}

但是当字符串 b 的长度比字符串 a 的长度长时,在运行时遇到了问题。对 len 和 pos 使用 auto 类型导致 pos 不是负数,而是像使用自然类型一样非常大的正值。对于这两个,将 auto 更改为 int,并且相同的测试用例有效。

    bool ends_with(std::string const &a, std::string const &b) {
        int len = b.length();
        int pos = a.length() - len;
        if (pos < 0)
            return false;
        auto pos_a = &a[pos];
        auto pos_b = &b[0];
        while (*pos_a)
            if (*pos_a++ != *pos_b++)
                return false;
        return true;
    }
© www.soinside.com 2019 - 2024. All rights reserved.