3

我正在做很多解析/处理,其中给出了前导/尾随空格和不区分大小写。所以我为std::basic_string(见下文)制作了一个基本的 char 特征,以节省一些工作。

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

如果 trait 的比较返回 0 ,那么为什么会有这个额外的“较短”排序?而且,是否有任何解决方法或者我必须自己滚动字符串?

#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;
}
4

2 回答 2

0

如果 trait 的比较返回 0,那么为什么会有这个额外的“较短”排序?

basic_string::compare()就是定义的方式。

而且,是否有任何解决方法或者我必须自己滚动字符串?

看来您的自定义char_traits必须实现:

  • length(),返回字符串修剪部分的长度,以及

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


但是,存在一个无法使用自定义特征解决的潜在问题。basic_string具有类似的构造函数basic_string(const CharT* s, size_type count, Allocator& alloc)或方法重载,如assignorcompare采用 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); }
};
于 2018-10-28T11:10:54.393 回答
0

将具有多种可能表示形式的数据转换为“标准”或“正常”形式称为规范化。对于文本,它通常意味着删除重音、大小写、修剪空白字符和/或格式字符。

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

如果 trait 的比较返回 0,那么为什么会有这个额外的“较短”排序?

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

于 2018-10-28T11:57:47.540 回答