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)
这样的构造函数,或者像 assign
或 compare
这样的方法重载,它们采用 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 格式字符。
如果在每次比较期间在幕后完成规范化,那么它是脆弱的。例如,您如何测试 s1
和 s2
是否正确完成?它也不灵活,例如你不能显示它的结果或缓存它以供下一次比较。
因此,将其作为显式规范化步骤来做更稳健、更有效。
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"
将比较相等,这可能是您不想要的。
我做了很多 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)
这样的构造函数,或者像 assign
或 compare
这样的方法重载,它们采用 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 格式字符。
如果在每次比较期间在幕后完成规范化,那么它是脆弱的。例如,您如何测试 s1
和 s2
是否正确完成?它也不灵活,例如你不能显示它的结果或缓存它以供下一次比较。
因此,将其作为显式规范化步骤来做更稳健、更有效。
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"
将比较相等,这可能是您不想要的。