Как сравнить с помощью std::lexicographical_compare две строки внутри std::vector без учета регистра?

Есть вектор строк. Как с помощью алгоритма std::lexicographical_compare можно сравнивать их внутри вектора между собой, а затем вывести отсортированный вектор?


Ответы (2 шт):

Автор решения: KoVadim

Похоже Вы хотите что то такое

#include <algorithm>
#include <iostream>
#include <vector>


int main()
{
    std::vector<std::string> data {"test", "boo", "foo"};
    std::sort(data.begin(), data.end(), [](const std::string& a, const std::string& b)->bool {
      return std::lexicographical_compare(a.begin(), a.end(),
                                          b.begin(), b.end());
    });
    for (auto a : data) {
        std::cout << a << "\n";
    }
}
→ Ссылка
Автор решения: Ariox

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


void case_insensitive_sort(std::vector<std::string&> vec){
    std::sort(data.begin(), data.end(),
        [](std::string lha, std::string rha){
            return std::lexicographical_compare(
                a.begin(), a.end(),
                b.begin(), b.end(),
                [](unsigned char c){ return std::tolower(c,  std::locale{}); });
        });
}

Этого достаточно для большинства задач при работе с ключами, но не для живых текстов.

Если вы используете однобайтовую кодировку, отличную от C-локали, нужно получить соответствующую локаль. В boost есть некоторые вспомогательные функции для этого, но в любом случае список доступных локалей зависит от системы, и вы не получите переносимое решение.

Единственный надежный и переносимый вариант - использовать широкие кодировки, т.е. либо std::u32string, либо std::string в кодировке utf8 (или std::u8string из C++20). Но одного этого недостаточно, у вас все еще нет надежной локали, реализующей toLower. Вам нужно найти стороннюю библиотеку, которая умеет в Unicode,и использовать ее для конвертации. Например, можно использовать Qt. Но в случае Qt строку придется копировать в QString, а потом обратно, лучше что-то получше найти. Если вы используете std::string, вылезает еще одна проблема: std::lexicographical_compare не работает с utf8, т.к. итератор std::string оперирует байтами, а не последовательностями.

Как вариант, можно использовать конкретную однобайтовую кодировку, например, cp1251, и написать для нее toLower самостоятельно. Это будет работать, пока кому-то не понадобится использовать, например, греческий символ.

→ Ссылка