std::sort(container.begin(), container.end(), std::locale());
Однако использовать подобный предикат для регистро-независимого сравнения строк не получится: std::collate::compare() возвращает ноль для полностью одинаковых строк (что означает их равенство), но вернет не ноль для одинаковых строк, различающихся регистром (например "hello" и "Hello").
Простой тест, чтобы показать несостоятельность std::collate::compare() (или его обертки в виде std::locale::operator()) для использования в ассоциативных контейнерах:
std::set<std::string, std::locale> s;Предикат std::locale не считает строки "hello" и "Hello" эквивалентными.
s.insert("hello");
s.insert("Hello");
std::cout << s.size(); // выведет 2
Брутальный подход - перевести строки в верхний регистр и уже тогда сравнивать:
template <class CharType>Такой предикат уже пройдет наш мини-тест.
void ToUpper(std::basic_string<CharType>& String, const std::locale& Locale)
{
if (!String.empty())
std::use_facet< std::ctype<CharType> >(Locale).toupper(&*String.begin(), &*String.begin() + String.size());
}
struct LexicographicalLess
{
LexicographicalLess(const std::locale& Loc = std::locale()) : Locale(Loc) {}
std::locale Locale;
template <typename CharType>
bool operator()(std::basic_string<CharType> lhs, std::basic_string<CharType> rhs) const
{
ToUpper(lhs, Locale);
ToUpper(rhs, Locale);
return Locale(lhs, rhs);
}
};
Однако скорость не впечатлит. В процессе сравнения делаются копии строк, что довольно долго. Особенно учитывая то, что std::basic_string хранит более-менее большие строки в динамической памяти.
Кстати, если предикат нужен только для сравнения строк, а не для сортировки (для сортировки у нас есть std::locale в качестве предиката), строку
return Locale(lhs, rhs);
можно заменить на более быструю return lhs < rhs;
, так как для сравнения нам не важно положение буквы в алфавите, сойдет и ее положение в кодовой таблице.Увеличить производительность LexicographicalLess можно избавившись от копирования строк:
struct LexicographicalLess
{
LexicographicalLess(const std::locale& Loc = std::locale()) : Locale(Loc) {}
std::locale Locale;
template <typename CharType>
bool operator()(CharType lhs, CharType rhs) const
{
return std::toupper(lhs, Locale) < std::toupper(rhs, Locale);
}
template <typename CharType>
bool operator()(const std::basic_string<CharType>& lhs, const std::basic_string<CharType>& rhs) const
{
return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end(), LexicographicalLess(Locale));
}
};
Еще немного дополнительной производительности мне удалось выжать написав свою версию
lexicographical_compare
.
Комментариев нет:
Отправить комментарий