Leading/trailing basic_string 的空格不敏感特征

Leading/trailing whitespace insensitive traits for basic_string

我做了很多 parsing/processing,其中 leading/trailing 空格和不区分大小写。所以我为 std::basic_string(见下文)制作了一个基本的字符特征,以节省一些工作。

特征不工作,问题是 basic_string 的比较调用特征比较,如果评估为 0,它 returns 大小差异。在 basic_string.h 它说 ...如果比较的结果是非零 returns 它,否则较短的先排序。 看起来他们明确地不不想让我这样做...

如果 trait 比较 returns 0,那么有这个额外的 "shorter one" 排序的原因是什么?而且,是否有任何解决方法,或者我是否必须滚动自己的字符串?

#include <cstring>
#include <iostream>

namespace csi{
template<typename T>
struct char_traits : std::char_traits<T>
{
    static int compare(T const*s1, T const*s2, size_t n){
        size_t n1(n);
        while(n1>0&&std::isspace(*s1))
            ++s1, --n1;
        while(n1>0&&std::isspace(s1[n1-1]))
            --n1;
        size_t n2(n);
        while(n2>0&&std::isspace(*s2))
            ++s2, --n2;
        while(n2>0&&std::isspace(s2[n2-1]))
            --n2;
        return strncasecmp(static_cast<char const*>(s1),
                           static_cast<char const*>(s2),
                           std::min(n1,n2));
    }
};
using string = std::basic_string<char,char_traits<char>>;
}

int main()
{
    using namespace csi;
    string s1 = "hello";
    string s2 = " HElLo ";
    std::cout << std::boolalpha
              << "s1==s2" << " " << (s1==s2) << std::endl;
}

What is the reason for having this additional "shorter one" ordering if trait's compare returns 0?

basic_string::compare() 就是 defined

And, is there any workaround or do I have to roll my own string?

看来您的自定义 char_traits 必须执行:

  • length(),返回字符串截断部分的长度,

  • move()copy(),用于复制修剪的部分


但是,存在一个无法使用自定义特征解决的潜在问题。 basic_string 有像 basic_string(const CharT* s, size_type count, Allocator& alloc) 这样的构造函数,或者像 assigncompare 这样的方法重载,它们采用 C 字符串及其长度 - 在这些情况下 Traits::length() 不会叫。如果有人使用其中一种方法,字符串可能包含尾随空格或尝试访问源字符串末尾以外的字符。

要解决这个问题,可以这样做:

class TrimmedString
{
public:
    // expose only "safe" methods:
    void assign(const char* s) { m_str.assign(s); }

private:
    std::basic_sttring<char, CustomTraits> m_str;
};

或者这个(可能更简单):

class TrimmedString : private std::basic_string<char, CustomTraits>
{
public:
    using BaseClass = std::basic_string<char, CustomTraits>; // for readability

    // make "safe" method public
    using BaseClass::length;
    using BaseClass::size;
    // etc.

    // wrappers for methods with "unsafe" overloads
    void assign(const char* s) { BaseClass::assign(s); }
};

将具有多种可能表示的数据转换为 "standard" 或 "normal" 形式称为规范化。对于文本,它通常意味着去除重音、大小写、修剪白色-space-字符and/or 格式字符。

如果在每次比较期间在幕后完成规范化,那么它是脆弱的。例如,您如何测试 s1s2 是否正确完成?它也不灵活,例如你不能显示它的结果或缓存它以供下一次比较。 因此,将其作为显式规范化步骤来做更稳健、更有效。

What is the reason for having this additional "shorter one" ordering if trait's compare returns 0?

特征比较只需要比较n个字符,所以当你比较"hellow""hello"时,它应该return?它应该 return 0。如果您以某种方式忽略 n ,那么您处于有缺陷的情况,因为这些特征应该与非零终止的 std::string_view 一起使用。如果删除大小比较,则 "hellow""hello" 将比较相等,这可能是您不想要的。