basic_string的前导/尾随空格不敏感特征

时间:2018-10-28 10:00:08

标签: c++ stdstring char-traits

我正在做很多解析/处理,其中给出了前导/后缀空格和不区分大小写的含义。因此,我为std::basic_string(请参见下文)创建了一个基本字符特征,以节省一些工作。

特征不起作用,问题在于basic_string的比较调用特征比较,如果计算为0,则返回大小差异。在basic_string.h中,它表示 ...如果比较的结果为非零,则返回它,否则比较短的将首先排序。看起来他们明确地不希望我这样做。 ..

如果特征的比较返回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;
}

2 个答案:

答案 0 :(得分:0)

  

如果特征的比较返回0,那么具有这种额外的“较短的一个”顺序的原因是什么?

basic_string::compare()defined的样子。

  

而且,有什么解决方法还是我必须滚动自己的字符串?

您的自定义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); }
};

答案 1 :(得分:0)

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

如果在每次比较期间都在后台进行规范化,则它很脆弱。例如,如何测试s2n是否都正确完成?它也不灵活,例如,您无法显示其结果或将其缓存以进行下一次比较。 因此,将其作为显式规范化步骤来进行既更健壮,又效率更高。

  

如果特征的比较返回0,那么具有这种额外的“较短的一个”顺序的原因是什么?

仅比较"hellow"个字符就需要进行特征比较,因此当比较"hello"0时,应该返回什么?它应该返回n。如果您以某种方式忽略了std::string_view,那么您就处于缺陷状态,因为特征应与不以零结尾的"hellow"一起使用。如果删除大小比较,则"hello"<?php $val1="I want this normal"; $val2="I want this normal"; $val3="I want this normal"; $val4="I want this RED"; echo "<table><tr>"; echo "<td>".$val1."</td>"; echo "<td>".$val2."</td>"; echo "<td>".$val3."</td>"; echo "<td style=\"background-color:red;\" >".$val4."</td>"; //Change the " for ' or escape " with \ echo "</tr></table>"; //And don't forget to close this tag too ;) 的比较结果可能相等,您可能不希望这样做。