Черты, не учитывающие пробелы в начале и в конце, для basic_string

Я делаю много разбора / обработки, где задаются пробелы в начале / в конце и нечувствительность к регистру. Итак, я сделал основную черту характера для 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;
}

3

Решение

Преобразование данных, имеющих более одного возможного представления, в «стандартную» или «нормальную» форму называется канонизацией. С текстом это обычно означает удаление акцентов, падежей, обрезку пробелов и / или символов форматирования.

Если во время каждого сравнения проводится канонизация под капотом, то она хрупкая. Например, как вы проверяете, что это было сделано правильно, чтобы s1 а также s2? Также он негибкий, например, вы не можете отобразить его результат или кэшировать его для следующего сравнения.
Так что это более надежный и эффективный способ сделать это как явный шаг канонизации.

В чем причина такого дополнительного «более короткого» порядка, если сравнение черты возвращает 0?

Сравнение черт требуется только для сравнения n символы, поэтому, когда вы сравниваете "hellow" а также "hello" что он должен вернуть? Должно вернуться 0, Вы находитесь в неисправной ситуации, если вы как-то игнорируете это n потому что черты должны работать с std::string_view это не заканчивается нулем. Если размер сравнения упал, то "hellow" а также "hello" сравнил бы равный что ты скорее всего не хочешь.

0

Другие решения

В чем причина такого дополнительного «более короткого» порядка, если сравнение черты возвращает 0?

Вот так просто basic_string::compare() является определенный.

И есть ли обходной путь или я должен свернуть свою собственную строку?

Кажется, что ваш обычай 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); }
};
0