Как я могу отсортировать std :: list с чувствительными к регистру элементами? - PullRequest
3 голосов
/ 27 февраля 2010

Это мой текущий код:

#include <list>
#include <string>
using std::string;
using std::list;

int main()
{
    list <string> list_;
    list_.push_back("C");
    list_.push_back("a");
    list_.push_back("b");

    list_.sort();
}

Сортирует ли функция sort() элементы по их кодам символов? Я хочу, чтобы результат был a b C после сортировки.

Ответы [ 5 ]

8 голосов
/ 27 февраля 2010

Сравнение символов без учета регистра сложно, если вы хотите поддерживать символы из других языков. Вот почему это хорошая идея, чтобы сделать их с учетом местных условий:

struct char_iless 
: public std::binary_function<char, char, bool>
{
    std::locale loc;

    char_iless(std::locale const & loc=std::locale()) : loc(loc) 
    {
    }

    bool operator()(char a, char b) const
    {
        return std::tolower(a, loc) < std::tolower(b, loc);
    }
};

Вот как вы используете этот класс для сравнения двух символов:

char_iless('a', 'b', my_locale);

Просто используйте std::locale() как my_locale, если хотите использовать тот, который установлен по умолчанию.

Если вы можете использовать Boost, тогда в библиотеке String Algorithms есть функтор am is_iless, который делает то же самое.

Расширить это от сравнения символов до строк легко благодаря std::lexicographical_compare:

struct str_iless 
: public std::binary_function<std::string, std::string, bool>
{
    std::locale loc;

    str_iless(std::locale const & loc=std::locale()) : loc(loc) 
    {
    }

    bool operator()(std::string const & a, std::string const & b) const
    {
        return std::lexicographical_compare(
            a.begin(), a.end(),
            b.begin(), b.end(),  
            char_iless(loc)
        );
    }
};

Теперь у вас есть все, что нужно для решения вашей проблемы:

int main()
{
    std::list<std::string> list;
    list.push_back("C");
    list.push_back("a");
    list.push_back("b");

    // Sort using default locale
    list.sort(str_iless());  

    // Sort using French locale 
    // (warning: this locale format string is MS specific)
    std::locale loc("French_France.1252");
    list.sort(str_iless(loc));
}
4 голосов
/ 27 февраля 2010

Компаратор по умолчанию (<) с использованием значения по умолчанию char_traits< char > отсортирует ваш список как C a b.

См. список :: сортировать .

Для достижения желаемого заказа a b C вы можете либо:

  1. составляет список string типов с custom char_traits, или
  2. предоставляет экземпляр пользовательского компаратора строк для sort, например,

    bool istring_less(const string& lhs, const string& rhs) {
      string::const_iterator \
        lb = lhs.begin(), le = lhs.end(),
        rb = rhs.begin(), re = rhs.end();
      const char lc, rc;
      for ( ; lb != le && rb != re; ++lb, ++rb) {
        lc = tolower(*lb);
        rc = tolower(*rb);
        if (*lc < *rc) return true;
        if (*lc > *rc) return false;
      }
      // if rhs is longer than lhs then lhs<rhs
      return (rb != re);
    }
    ...
    list.sort(istring_less);
    
1 голос
/ 10 июня 2010

Вот что я считаю более чистой и значительно более быстрой альтернативой:

#include    <string>
#include    <cstring>
#include    <iostream>
#include    <boost/algorithm/string.hpp>

using std::string;
using std::list;
using std::cout;
using std::endl;

using namespace boost::algorithm;

// recommended in Meyers, Effective STL when internationalization and embedded
// NULLs aren't an issue.  Much faster than the STL or Boost lex versions.
struct ciLessLibC : public std::binary_function<string, string, bool> {
    bool operator()(const string &lhs, const string &rhs) const {
        return strcasecmp(lhs.c_str(), rhs.c_str()) < 0 ? 1 : 0;
    }
};

// If you need sorting according to the default system local
struct ciLessBoost : std::binary_function<std::string, std::string, bool>
{
    bool operator() (const std::string & s1, const std::string & s2) const {
        return lexicographical_compare(s1, s2, is_iless());
    }
};

int main(void) {
    list <string> list_;
    list_.push_back("C");
    list_.push_back("a");
    list_.push_back("b");

    list_.sort(ciLessLibC());
    list_.sort(ciLessBoost());

    return 0;
}
0 голосов
/ 05 июля 2018

Поскольку C ++ 11 , вы также можете использовать лямбда-выражение вместо определения функции / структуры сравнения:

#include <list>
#include <string>
#include <cstring>
#include <iostream>
using namespace std;

int main()
{
    list<string> list_;
    list_.emplace_back("C");
    list_.emplace_back("a");
    list_.emplace_back("b");

    list_.sort([](const string& a, const string& b) {
        return (strcasecmp(a.c_str(), b.c_str()) < 0);
    });

    for (auto const &str : list_)
        cout << str << endl;

    return 0;
}  

Выход:

а
б
C

Примечание: функция strcasecmp() (как также предлагается в ответе @ RobertS.Barnes) не входит в стандарт C ++ и, следовательно, доступна не во всех системах. Например, если вы используете Visual Studio, вместо этого вы можете использовать _stricmp().

Если для вас важна интернационализация, вы можете применить локаль, как @Manuel в своем ответе.

Код на Ideone

0 голосов
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...