Сведения о вопросе

Mathprofi

04:03, 28th August, 2020

Теги

c++   string    

Сравнение строк без учета регистра в C++

Просмотров: 1887   Ответов: 5

Как лучше всего выполнить сравнение строк без учета регистра в C++ без преобразования строки во все прописные или все строчные буквы?

Просьба указать, насколько эти методы удобны для использования в Юникоде и насколько они портативны.



  Сведения об ответе

ЯЯ__4

02:55, 7th August, 2020

Boost включает в себя удобный алгоритм для этого:

#include <boost/algorithm/string.hpp>
// Or, for fewer header dependencies:
//#include <boost/algorithm/string/predicate.hpp>

std::string str1 = "hello, world!";
std::string str2 = "HELLO, WORLD!";

if (boost::iequals(str1, str2))
{
    // Strings are identical
}


  Сведения об ответе

darknet

11:50, 3rd August, 2020

Воспользуйтесь преимуществами стандарта char_traits . Напомним, что std::string -это фактически typedef для std::basic_string<char>, или более явно, std::basic_string<char, std::char_traits<char> > . Тип char_traits описывает, как символы сравниваются, как они копируются, как они разыгрываются и т. д. Все , что вам нужно сделать, это ввести новую строку поверх basic_string и предоставить ей свой собственный пользовательский char_traits , который сравнивает регистр нечувствительно.

struct ci_char_traits : public char_traits<char> {
    static bool eq(char c1, char c2) { return toupper(c1) == toupper(c2); }
    static bool ne(char c1, char c2) { return toupper(c1) != toupper(c2); }
    static bool lt(char c1, char c2) { return toupper(c1) <  toupper(c2); }
    static int compare(const char* s1, const char* s2, size_t n) {
        while( n-- != 0 ) {
            if( toupper(*s1) < toupper(*s2) ) return -1;
            if( toupper(*s1) > toupper(*s2) ) return 1;
            ++s1; ++s2;
        }
        return 0;
    }
    static const char* find(const char* s, int n, char a) {
        while( n-- > 0 && toupper(*s) != toupper(a) ) {
            ++s;
        }
        return s;
    }
};

typedef std::basic_string<char, ci_char_traits> ci_string;

Подробности - на Гуру недели № 29 .


  Сведения об ответе

dump

11:04, 10th August, 2020

Проблема с boost заключается в том, что вам приходится связываться с boost и зависеть от него. В некоторых случаях это непросто (например, android).

А использование char_traits означает, что все ваши сравнения нечувствительны к регистру, а это обычно не то, что вы хотите.

Этого должно быть достаточно. Она должна быть достаточно эффективной. Однако он не обрабатывает unicode или что-то еще.

bool iequals(const string& a, const string& b)
{
    unsigned int sz = a.size();
    if (b.size() != sz)
        return false;
    for (unsigned int i = 0; i < sz; ++i)
        if (tolower(a[i]) != tolower(b[i]))
            return false;
    return true;
}

Обновление: бонусная версия C++14 ( #include <algorithm> ):

bool iequals(const string& a, const string& b)
{
    return std::equal(a.begin(), a.end(),
                      b.begin(), b.end(),
                      [](char a, char b) {
                          return tolower(a) == tolower(b);
                      });
}


  Сведения об ответе

COOL

21:51, 11th August, 2020

Если вы находитесь в системе POSIX, вы можете использовать strcasecmp . Эта функция не является частью стандарта C, хотя и не доступна на Windows. Это будет выполнять сравнение без учета регистра на 8-битных символах, пока locale является POSIX. Если locale не является POSIX, то результаты не определены (поэтому он может выполнить локализованное сравнение, а может и нет). Эквивалент широкого символа недоступен.

В противном случае большое количество исторических реализаций библиотеки C имеют функции stricmp() и strnicmp(). Visual C++ на Windows переименовал все эти объекты, добавив к ним префикс с подчеркиванием, поскольку они не являются частью стандарта ANSI, поэтому в этой системе они называются _stricmp или _strnicmp . Некоторые библиотеки могут также иметь широкий характер или многобайтовых эквивалентных функций (обычно называемых например, wcsicmp, mbcsicmp и так далее).

C и C++ в основном не знают о проблемах интернационализации, поэтому хорошего решения этой проблемы нет, кроме как использовать стороннюю библиотеку. Проверьте IBM ICU (International Components for Unicode) , если вам нужна надежная библиотека для C/C++. ICU is для систем Windows и Unix.


  Сведения об ответе

dump

03:19, 4th August, 2020

Вы имеете в виду тупое сравнение без учета регистра или полное нормализованное сравнение Unicode?

Тупое сравнение не найдет строк, которые могут быть одинаковыми, но не являются двоичными равными.

Пример:

U212B (ANGSTROM SIGN)
U0041 (LATIN CAPITAL LETTER A) + U030A (COMBINING RING ABOVE)
U00C5 (LATIN CAPITAL LETTER A WITH RING ABOVE).

Все они эквивалентны, но также имеют различные бинарные представления.

Тем не менее, нормализация Юникода должна быть обязательным чтением, особенно если вы планируете поддерживать хангыль, Таи и другие азиатские языки.

Кроме того, IBM в значительной степени запатентовал наиболее оптимизированные алгоритмы Юникода и сделал их общедоступными. Они также поддерживают реализацию: IBM ICU


Ответить на вопрос

Чтобы ответить на вопрос вам нужно войти в систему или зарегистрироваться