Я делаю много разбора / обработки, где задаются пробелы в начале / в конце и нечувствительность к регистру. Итак, я сделал основную черту характера для 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;
}
Преобразование данных, имеющих более одного возможного представления, в «стандартную» или «нормальную» форму называется канонизацией. С текстом это обычно означает удаление акцентов, падежей, обрезку пробелов и / или символов форматирования.
Если во время каждого сравнения проводится канонизация под капотом, то она хрупкая. Например, как вы проверяете, что это было сделано правильно, чтобы s1
а также s2
? Также он негибкий, например, вы не можете отобразить его результат или кэшировать его для следующего сравнения.
Так что это более надежный и эффективный способ сделать это как явный шаг канонизации.
В чем причина такого дополнительного «более короткого» порядка, если сравнение черты возвращает 0?
Сравнение черт требуется только для сравнения n
символы, поэтому, когда вы сравниваете "hellow"
а также "hello"
что он должен вернуть? Должно вернуться 0
, Вы находитесь в неисправной ситуации, если вы как-то игнорируете это n
потому что черты должны работать с std::string_view
это не заканчивается нулем. Если размер сравнения упал, то "hellow"
а также "hello"
сравнил бы равный что ты скорее всего не хочешь.
В чем причина такого дополнительного «более короткого» порядка, если сравнение черты возвращает 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); }
};