【问题标题】:C++ std:: string starts_with/ends_with case insensitive versions?C++ std::stringstarts_with/ends_with 不区分大小写的版本?
【发布时间】:2020-09-02 19:03:15
【问题描述】:

C++20 添加了starts_with,ends_with 到 std::string。

有没有一个很好的方法让它区分大小写in

请注意,性能很重要,因此我不想将两个字符串(或其中的 std::min(len1, len2) 部分)都小写/大写。

与常规的 <algorithm> 算法不同,starts_with 没有比较器过载,所以我看不出有什么好的方法。

而且我有点理解 90% 以上的情况是区分大小写的,除非非常有用,否则 C++ 中的成员 fns 会被避免......所以我知道为什么会存在这个限制,我只是好奇是否可以使用相对可读的东西在 C++20 中一起破解,而我没有使用自定义比较器手动调用 std::equal(或范围版本的 equal)。

【问题讨论】:

  • Does this answer your question? 仅将它用于这两个功能需要一些额外的查看/复制代码,但为了避免复制,请注意它也适用于string_view。但是,无论如何,更严格的性能要求可能会更好地使用 SIMD 实现,具体取决于编译器+标准库的优化程度。
  • @chris 不是真的,我不想要不区分大小写的字符串类,我想要 std::string 的不区分大小写比较
  • 如果您不关心大小写,为什么不将所有字符串存储在一个大小写中?
  • @NoSenseEtAl,我的意思是您可以在区分大小写的字符串上创建不区分大小写的视图。
  • @NathanOliver:这可能是不必要的复杂化是有原因的,例如用户可能将他的文件命名为 MyLog.log 并且他希望看到它在 UI 中显示为 MyLog.log,即使我们在内部只需检查文件是否不区分大小写以 .log 结尾(因为这是我们允许的)。

标签: c++ c++20 stdstring stl-algorithm std-ranges


【解决方案1】:

我很想知道申请 this answer 的建议是如何实现的。这就是结果。

上述答案的代码:

struct ci_char_traits : public char_traits<char> {
    static bool eq(char c1, char c2) { return toupper(c1) == toupper(c2); }
    static bool ne(char c1, char c2) { return toupper(c1) != toupper(c2); }
    static bool lt(char c1, char c2) { return toupper(c1) <  toupper(c2); }
    static int compare(const char* s1, const char* s2, size_t n) {
        while( n-- != 0 ) {
            if( toupper(*s1) < toupper(*s2) ) return -1;
            if( toupper(*s1) > toupper(*s2) ) return 1;
            ++s1; ++s2;
        }
        return 0;
    }
    static const char* find(const char* s, int n, char a) {
        while( n-- > 0 && toupper(*s) != toupper(a) ) {
            ++s;
        }
        return s;
    }
};

typedef std::basic_string<char, ci_char_traits> ci_string;

那里的答案建议使用ci_string 而不是std::string。这里我们只想创建ci_viewsstd::strings:

typedef std::basic_string_view<char, ci_char_traits> ci_string_view;

int main()
{   
    std::string x{"ABCD"};
    std::string y{"abcd"};
    std::cout << ci_string_view{x.begin(),x.end()}.ends_with(ci_string_view{y.begin(),y.end()});
}

输出:

1

Live Example

【讨论】:

  • 你编译了吗,我得到:source>:33:12: error: no matching constructor for initialization of 'ci_string_view' (aka 'basic_string_view') return ci_string_view{value. begin(), value.end()}.ends_with(ci_string_view{ending.begin(), ending.end()));
  • @NoSenseEtAl godbolt.org/z/Ee86K8 它的 gcc 10.2,不确定 C++20 支持的当前状态,现在应该或多或少完成
  • clang 背叛了我 :) godbolt.org/z/d58v6T 谢谢你的链接,我愚蠢地假设如果任何编译器编译它,那么它就是 clang。 :)
  • 顺便说一句,删除 find 似乎并没有破坏任何东西,如果需要,您知道为什么需要它吗?
  • @NoSenseEtAl 原始答案下的 cmets 有一些很好的建议,例如 int 应该是 size_t,虽然我只是按原样引用
【解决方案2】:

std::mismatch(s1.begin(), s1.end(), s2.begin(), s2.end(), &lt;comparator&gt;) 会做你想做的事。您必须编写不区分大小写的比较器,但我相信您可以解决这个问题。

【讨论】:

  • 很好,对于未来的读者来说如何检查谓词可能并不明显(将返回对元素之一与 .end() 进行比较,但这应该很好用。
【解决方案3】:

我最近也遇到了这个问题。

如果你不介意使用 boost,还有 istarts_withiends_with 函数。

他们完全满足您的需求。

【讨论】:

    猜你喜欢
    • 2011-03-10
    • 2011-04-27
    • 2022-11-12
    • 1970-01-01
    • 2023-03-15
    • 2017-12-01
    • 1970-01-01
    相关资源
    最近更新 更多