Нечувствительное к регистру сравнение строк в [закрытом] C++

Ответ vorrtex не сработал для меня, но я взял много от него и придумал свое решение. Вот он:

package ie.moses.keepitlocal.util;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.support.annotation.IntRange;
import android.text.Layout;
import android.text.style.LeadingMarginSpan;
import android.view.View;
import android.widget.TextView;

import ie.moses.keepitlocal.util.MeasurementUtils;
import ie.moses.keepitlocal.util.TextUtils;

import static com.google.common.base.Preconditions.checkArgument;

public class WrapViewSpan implements LeadingMarginSpan.LeadingMarginSpan2 {

    private final Context _context;
    private final int _lineCount;
    private int _leadingMargin;
    private int _padding;

    public WrapViewSpan(View wrapeeView, TextView wrappingView) {
        this(wrapeeView, wrappingView, 0);
    }

    /**
     * @param padding Padding in DIP.
     */
    public WrapViewSpan(View wrapeeView, TextView wrappingView, @IntRange(from = 0) int padding) {
        _context = wrapeeView.getContext();
        setPadding(padding);

        int wrapeeHeight = wrapeeView.getHeight();
        float lineHeight = TextUtils.getLineHeight(wrappingView);

        int lineCnt = 0;
        float linesHeight = 0F;
        while ((linesHeight += lineHeight) <= wrapeeHeight) {
            lineCnt++;
        }

        _lineCount = lineCnt;
        _leadingMargin = wrapeeView.getWidth();
    }

    public void setPadding(@IntRange(from = 0) int paddingDp) {
        checkArgument(paddingDp >= 0, "padding cannot be negative");
        _padding = (int) MeasurementUtils.dpiToPixels(_context, paddingDp);
    }

    @Override
    public int getLeadingMarginLineCount() {
        return _lineCount;
    }

    @Override
    public int getLeadingMargin(boolean first) {
        if (first) {
            return _leadingMargin + _padding;
        } else {
            return _padding;
        }
    }

    @Override
    public void drawLeadingMargin(Canvas c, Paint p, int x, int dir, int top, int baseline,
                                  int bottom, CharSequence text, int start, int end,
                                  boolean first, Layout layout) {

    }

}

и в моем фактическом классе, где используется диапазон:

ViewTreeObserver headerViewTreeObserver = _headerView.getViewTreeObserver();
headerViewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
    @Override
    public void onGlobalLayout() {
        String descriptionText = _descriptionView.getText().toString();
        SpannableString spannableDescriptionText = new SpannableString(descriptionText);
        LeadingMarginSpan wrapHeaderSpan = new WrapViewSpan(_headerView, _descriptionView, 12);
        spannableDescriptionText.setSpan(
                wrapHeaderSpan,
                0,
                spannableDescriptionText.length(),
                Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
        );
        _descriptionView.setText(spannableDescriptionText);
        ViewTreeObserver headerViewTreeObserver = _headerView.getViewTreeObserver();
        headerViewTreeObserver.removeOnGlobalLayoutListener(this);
    }
});

Мне нужен глобальный приемник макета, чтобы получить правильные значения для getWidth() и getHeight().

Вот результат:

373
задан Toby Speight 23 August 2017 в 16:35
поделиться

31 ответ

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

#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
}
308
ответ дан Josh Kelley 23 August 2017 в 16:35
поделиться
bool insensitive_c_compare(char A, char B){
  static char mid_c = ('Z' + 'a') / 2 + 'Z';
  static char up2lo = 'A' - 'a'; /// the offset between upper and lowers

  if ('a' >= A and A >= 'z' or 'A' >= A and 'Z' >= A)
      if ('a' >= B and B >= 'z' or 'A' >= B and 'Z' >= B)
      /// check that the character is infact a letter
      /// (trying to turn a 3 into an E would not be pretty!)
      {
        if (A > mid_c and B > mid_c or A < mid_c and B < mid_c)
        {
          return A == B;
        }
        else
        {
          if (A > mid_c)
            A = A - 'a' + 'A'; 
          if (B > mid_c)/// convert all uppercase letters to a lowercase ones
            B = B - 'a' + 'A';
          /// this could be changed to B = B + up2lo;
          return A == B;
        }
      }
}

это, вероятно, можно сделать гораздо более эффективным, но вот громоздкая версия со всеми ее битами.

не такой портативный, но хорошо работает с тем, что есть на моем компьютере (не знаю, я из картинок, а не слов)

-1
ответ дан user4578093 23 August 2017 в 16:35
поделиться

Простой способ сравнить две строки в c ++ (проверено для windows) - использовать _stricmp

// Case insensitive (could use equivalent _stricmp)  
result = _stricmp( string1, string2 );  

Если вы хотите использовать с std :: string, пример:

std::string s1 = string("Hello");
if ( _stricmp(s1.c_str(), "HELLO") == 0)
   std::cout << "The string are equals.";

Для получения дополнительной информации здесь: https://msdn.microsoft.com/it-it/library/e0z9k731.aspx

0
ответ дан eyllanesc 23 August 2017 в 16:35
поделиться

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

std::wstring first = L"Test";
std::wstring second = L"TEST";

std::wregex pattern(first, std::wregex::icase);
bool isEqual = std::regex_match(second, pattern);
0
ответ дан smibe 23 August 2017 в 16:35
поделиться

Если у вас есть вектор строк, например:

std::sort(std::begin(myvector), std::end(myvector), [](std::string const &a, std::string const &b)
{
    return std::lexicographical_compare(std::begin(a), std::end(a), std::begin(b), std::end(b), [](std::string::value_type a, std::string::value_type b)
    {
        return std::tolower(a) < std::tolower(b); //case-insensitive
    });
});

http://ideone.com/N6sq6X

0
ответ дан LB-- 23 August 2017 в 16:35
поделиться

Если вы не хотите использовать Boost-библиотеку , то здесь есть решение, использующее только стандартный C ++ заголовок io.

#include <iostream>

struct iequal
{
    bool operator()(int c1, int c2) const
    {
        // case insensitive comparison of two characters.
        return std::toupper(c1) == std::toupper(c2);
    }
};

bool iequals(const std::string& str1, const std::string& str2)
{
    // use std::equal() to compare range of characters using the functor above.
    return std::equal(str1.begin(), str1.end(), str2.begin(), iequal());
}

int main(void)
{
    std::string str_1 = "HELLO";
    std::string str_2 = "hello";

    if(iequals(str_1,str_2))
    {
        std::cout<<"String are equal"<<std::endl;   
    }

    else
    {
        std::cout<<"String are not equal"<<std::endl;
    }


    return 0;
}
1
ответ дан Richard Chambers 23 August 2017 в 16:35
поделиться

В начале 2013 года проект ICU, поддерживаемый IBM, является довольно хорошим ответом на это.

http://site.icu-project.org/

ICU - это «полная, портативная библиотека Unicode, которая близко отслеживает отраслевые стандарты». Для конкретной задачи сравнения строк объект Collation делает то, что вы хотите.

Проект Mozilla принял ICU для интернационализации в Firefox в середине 2012 года; обсуждение технических вопросов, включая вопросы о системах сборки и размере файла данных, можно найти здесь:

2
ответ дан michaelhanson 23 August 2017 в 16:35
поделиться

Поздно к вечеринке, но вот вариант, который использует std::locale и, следовательно, правильно обрабатывает турецкий язык:

auto tolower = std::bind1st(
    std::mem_fun(
        &std::ctype<char>::tolower),
    &std::use_facet<std::ctype<char> >(
        std::locale()));

дает вам функтор, который использует активную локаль для преобразования символов в строчные, затем вы можете использовать std::transform для генерации строчных букв:

std::string left = "fOo";
transform(left.begin(), left.end(), left.begin(), tolower);

Это также работает для строк на основе wchar_t.

2
ответ дан Simon Richter 23 August 2017 в 16:35
поделиться

Простой способ сравнения строк, которые различаются только строчными и заглавными буквами, состоит в сравнении ascii. Все прописные и строчные буквы различаются на 32 бита в таблице ASCII, используя эту информацию, мы имеем следующее ...

    for( int i = 0; i < string2.length(); i++)
    {
       if (string1[i] == string2[i] || int(string1[i]) == int(string2[j])+32 ||int(string1[i]) == int(string2[i])-32) 
    {
      count++;
      continue;
    }
    else 
    {
      break;
    }
    if(count == string2.length())
    {
      //then we have a match
    }
}
-3
ответ дан HaveNoDisplayName 23 August 2017 в 16:35
поделиться

У меня был хороший опыт использования Международных Компонентов для библиотек Unicode - они чрезвычайно мощные и предоставляют методы для преобразования, поддержки локали, рендеринга даты и времени, отображения дел (что вам не нужно t, кажется, хотят), и сопоставление , которое включает сравнение без учета регистра и акцента (и многое другое). Я использовал только версию библиотек на C ++, но, похоже, они также имеют версию Java.

Существуют методы для выполнения нормализованного сравнения, на которые ссылается @Coincoin, и они могут даже учитывать локаль - например (и это пример сортировки, а не строго равенство), традиционно на испанском (в Испании) буква комбинация "ll" сортирует между "l" и "m", поэтому "lz" < "ll" < "Ма".

4
ответ дан Blair Conrad 23 August 2017 в 16:35
поделиться

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

#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
string tolow(string a)
{
    for(unsigned int i=0;i<a.length();i++)
    {
        a[i]=tolower(a[i]);
    }
    return a;
}
int main()
{
    string str1,str2;
    cin>>str1>>str2;
    int temp=tolow(str1).compare(tolow(str2));
    if(temp>0)
        cout<<1;
    else if(temp==0)
        cout<<0;
    else
        cout<<-1;
}
2
ответ дан Jagadeesh Pulamarasetti 23 August 2017 в 16:35
поделиться

Для этого без использования Boost можно получить указатель на строку C с помощью c_str() и использовать strcasecmp:

std::string str1 ="aBcD";
std::string str2 = "AbCd";;
if (strcasecmp(str1.c_str(), str2.c_str()) == 0)
{
    //case insensitive equal 
}
6
ответ дан DavidS 23 August 2017 в 16:35
поделиться

Просто используйте strcmp() для чувствительности к регистру и strcmpi() или stricmp() для сравнения без учета регистра. Оба из которых находятся в заголовочном файле <string.h>

формат:

int strcmp(const char*,const char*);    //for case sensitive
int strcmpi(const char*,const char*);   //for case insensitive

Использование:

string a="apple",b="ApPlE",c="ball";
if(strcmpi(a.c_str(),b.c_str())==0)      //(if it is a match it will return 0)
    cout<<a<<" and "<<b<<" are the same"<<"\n";
if(strcmpi(a.c_str(),b.c_str()<0)
    cout<<a[0]<<" comes before ball "<<b[0]<<", so "<<a<<" comes before "<<b;

Выходные данные

apple и ApPlE одинаковы

a предшествует b, поэтому apple предшествует мячу

4
ответ дан reubenjohn 23 August 2017 в 16:35
поделиться

Просто обратите внимание на то, какой метод вы в конечном итоге выберете, если этот метод включает в себя использование strcmp, которое предлагают некоторые ответы:

strcmp не работает с данными Unicode в целом. В целом, он даже не работает с байтовыми кодировками Unicode, такими как utf-8, поскольку strcmp выполняет только байтовое сравнение, а кодовые точки Unicode, закодированные в utf-8, могут занимать более 1 байта. Единственный конкретный случай Unicode strcmp, который правильно обрабатывается, - это когда строка, закодированная с помощью байтовой кодировки, содержит только кодовые точки ниже U + 00FF - тогда достаточно сравнения байтов на байты.

2
ответ дан Johann Gerell 23 August 2017 в 16:35
поделиться
std::equal(str1.begin(), str1.end(), str2.begin(), [](auto a, auto b){return std::tolower(a)==std::tolower(b);})

Вы можете использовать приведенный выше код на C ++ 14, если вы не в состоянии использовать boost. Вы должны использовать std::towlower для широких символов.

9
ответ дан vine'th 23 August 2017 в 16:35
поделиться

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

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

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

53
ответ дан alastair 23 August 2017 в 16:35
поделиться

Библиотека Boost.String имеет множество алгоритмов для сравнения без учета регистра и т. Д.

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

11
ответ дан Dean Harding 23 August 2017 в 16:35
поделиться

Моей первой мыслью для не-юникодной версии было сделать что-то вроде этого:


bool caseInsensitiveStringCompare(const string& str1, const string& str2) {
    if (str1.size() != str2.size()) {
        return false;
    }
    for (string::const_iterator c1 = str1.begin(), c2 = str2.begin(); c1 != str1.end(); ++c1, ++c2) {
        if (tolower(*c1) != tolower(*c2)) {
            return false;
        }
    }
    return true;
}
28
ответ дан Shadow2531 23 August 2017 в 16:35
поделиться

Я написал версию char_traits без учета регистра для использования с std :: basic_string, чтобы генерировать std :: string, которая не чувствительна к регистру при выполнении сравнений, поисков и т. Д. С использованием встроенной std :: basic_string функции-члены.

Другими словами, я хотел сделать что-то подобное.

std::string a = "Hello, World!";
std::string b = "hello, world!";

assert( a == b );

... который std :: string не может обработать. Вот использование моих новых char_traits:

std::istring a = "Hello, World!";
std::istring b = "hello, world!";

assert( a == b );

... и вот реализация:

/*  ---

        Case-Insensitive char_traits for std::string's

        Use:

            To declare a std::string which preserves case but ignores case in comparisons & search,
            use the following syntax:

                std::basic_string<char, char_traits_nocase<char> > noCaseString;

            A typedef is declared below which simplifies this use for chars:

                typedef std::basic_string<char, char_traits_nocase<char> > istring;

    --- */

    template<class C>
    struct char_traits_nocase : public std::char_traits<C>
    {
        static bool eq( const C& c1, const C& c2 )
        { 
            return ::toupper(c1) == ::toupper(c2); 
        }

        static bool lt( const C& c1, const C& c2 )
        { 
            return ::toupper(c1) < ::toupper(c2);
        }

        static int compare( const C* s1, const C* s2, size_t N )
        {
            return _strnicmp(s1, s2, N);
        }

        static const char* find( const C* s, size_t N, const C& a )
        {
            for( size_t i=0 ; i<N ; ++i )
            {
                if( ::toupper(s[i]) == ::toupper(a) ) 
                    return s+i ;
            }
            return 0 ;
        }

        static bool eq_int_type( const int_type& c1, const int_type& c2 )
        { 
            return ::toupper(c1) == ::toupper(c2) ; 
        }       
    };

    template<>
    struct char_traits_nocase<wchar_t> : public std::char_traits<wchar_t>
    {
        static bool eq( const wchar_t& c1, const wchar_t& c2 )
        { 
            return ::towupper(c1) == ::towupper(c2); 
        }

        static bool lt( const wchar_t& c1, const wchar_t& c2 )
        { 
            return ::towupper(c1) < ::towupper(c2);
        }

        static int compare( const wchar_t* s1, const wchar_t* s2, size_t N )
        {
            return _wcsnicmp(s1, s2, N);
        }

        static const wchar_t* find( const wchar_t* s, size_t N, const wchar_t& a )
        {
            for( size_t i=0 ; i<N ; ++i )
            {
                if( ::towupper(s[i]) == ::towupper(a) ) 
                    return s+i ;
            }
            return 0 ;
        }

        static bool eq_int_type( const int_type& c1, const int_type& c2 )
        { 
            return ::towupper(c1) == ::towupper(c2) ; 
        }       
    };

    typedef std::basic_string<char, char_traits_nocase<char> > istring;
    typedef std::basic_string<wchar_t, char_traits_nocase<wchar_t> > iwstring;
6
ответ дан John Dibling 23 August 2017 в 16:35
поделиться

Проблема с бустом в том, что вы должны связываться с бустом и зависеть от него. Нелегко в некоторых случаях (например, 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);
                      });
}
69
ответ дан Timmmm 23 August 2017 в 16:35
поделиться

boost :: iequals не совместим с utf-8 в случае строки. Вы можете использовать boost :: locale .

comparator<char,collator_base::secondary> cmpr;
cout << (cmpr(str1, str2) ? "str1 < str2" : "str1 >= str2") << endl;
  • Primary - игнорировать ударения и регистр символов, сравнивая только базовые буквы. Например, «фасад» и «фасад» - это одно и то же.
  • Вторичный - игнорировать регистр символов, но учитывать акценты. «Фасад» и «фасад» различны, но «Фасад» и «Фасад» одинаковы.
  • Третичный - рассмотрим как падеж, так и ударения: «Фасад» и «Фасад» различны. Игнорировать знаки препинания.
  • Четвертичный - рассмотреть все случаи, акценты и знаки препинания. Слова должны быть идентичны с точки зрения представления Unicode.
  • Идентично - как четвертичное, но сравните также и кодовые точки.
31
ответ дан Igor Milyakov 23 August 2017 в 16:35
поделиться

Строковые функции Visual C ++, поддерживающие юникод: http://msdn.microsoft.com/en-us/library/cc194799.aspx

, вероятно, вы ищете _wcsnicmp

14
ответ дан Yu Hao 23 August 2017 в 16:35
поделиться

Вы можете использовать strcasecmp в Unix или stricmp в Windows.

Одна вещь, о которой до сих пор не упоминалось, заключается в том, что если вы используете строки stl с этими методами, полезно сначала сравнить длину двух строк, поскольку эта информация уже доступна вам в классе строк. Это может помешать проведению дорогостоящего сравнения строк, если сравниваемые две строки имеют даже разную длину.

16
ответ дан Yu Hao 23 August 2017 в 16:35
поделиться

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

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

Конечно, вы можете «скрыть» это преобразование за своей собственной строковой функцией или классом, но вам все равно нужно преобразовать строки перед сравнением.

6
ответ дан Andrew Grant 23 August 2017 в 16:35
поделиться

FYI, strcmp() и stricmp() уязвимы для переполнения буфера, так как они просто обрабатывают, пока не достигнут нулевого терминатора. Безопаснее использовать _strncmp() и _strnicmp() .

10
ответ дан Yu Hao 23 August 2017 в 16:35
поделиться

Я пытаюсь собрать хороший ответ из всех постов, поэтому помогите мне отредактировать это:

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

bool caseInsensitiveStringCompare( const std::string& str1, const std::string& str2 ) {
    std::string str1Cpy( str1 );
    std::string str2Cpy( str2 );
    std::transform( str1Cpy.begin(), str1Cpy.end(), str1Cpy.begin(), ::tolower );
    std::transform( str2Cpy.begin(), str2Cpy.end(), str2Cpy.begin(), ::tolower );
    return ( str1Cpy == str2Cpy );
}

Из того, что я прочитал, это более переносимо, чем stricmp (), потому что stricmp () на самом деле не является частью библиотеки std, но реализуется только большинство поставщиков компиляторов.

Чтобы получить действительно дружественную для Unicode реализацию, кажется, вы должны выйти за пределы библиотеки std. Одной из хороших сторонних библиотек является IBM ICU (International Components for Unicode)

Также boost :: iequals предоставляет довольно хорошую утилиту для проведения такого рода сравнения.

13
ответ дан 7 revs 23 August 2017 в 16:35
поделиться

Коротко и красиво. Никаких других зависимостей, кроме , расширенного стандарта C lib.

strcasecmp(str1.c_str(), str2.c_str()) == 0

возвращает true , если str1 и str2 равны. strcasecmp может не существовать, могут быть аналоги stricmp, strcmpi и т. Д.

Пример кода:

#include <iostream>
#include <string>
#include <string.h> //For strcasecmp(). Also could be found in <mem.h>

using namespace std;

/// Simple wrapper
inline bool str_ignoreCase_cmp(std::string const& s1, std::string const& s2) {
    if(s1.length() != s2.length())
        return false;  // optimization since std::string holds length in variable.
    return strcasecmp(s1.c_str(), s2.c_str()) == 0;
}

/// Function object - comparator
struct StringCaseInsensetiveCompare {
    bool operator()(std::string const& s1, std::string const& s2) {
        if(s1.length() != s2.length())
            return false;  // optimization since std::string holds length in variable.
        return strcasecmp(s1.c_str(), s2.c_str()) == 0;
    }
    bool operator()(const char *s1, const char * s2){ 
        return strcasecmp(s1,s2)==0;
    }
};


/// Convert bool to string
inline char const* bool2str(bool b){ return b?"true":"false"; }

int main()
{
    cout<< bool2str(strcasecmp("asd","AsD")==0) <<endl;
    cout<< bool2str(strcasecmp(string{"aasd"}.c_str(),string{"AasD"}.c_str())==0) <<endl;
    StringCaseInsensetiveCompare cmp;
    cout<< bool2str(cmp("A","a")) <<endl;
    cout<< bool2str(cmp(string{"Aaaa"},string{"aaaA"})) <<endl;
    cout<< bool2str(str_ignoreCase_cmp(string{"Aaaa"},string{"aaaA"})) <<endl;
    return 0;
}

Выход:

true
true
true
true
true
7
ответ дан kyb 23 August 2017 в 16:35
поделиться

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

Итак, я пришел к следующему:

bool icasecmp(const string& l, const string& r)
{
    return l.size() == r.size()
        && equal(l.cbegin(), l.cend(), r.cbegin(),
            [](string::value_type l1, string::value_type r1)
                { return toupper(l1) == toupper(r1); });
}

bool icasecmp(const wstring& l, const wstring& r)
{
    return l.size() == r.size()
        && equal(l.cbegin(), l.cend(), r.cbegin(),
            [](wstring::value_type l1, wstring::value_type r1)
                { return towupper(l1) == towupper(r1); });
}

Простая функция с одной перегрузкой для char и другой для whar_t. Не использует ничего нестандартного, поэтому должно работать на любой платформе.

Сравнение равенства не учитывает такие проблемы, как кодирование переменной длины и нормализация Unicode, но basic_string не поддерживает этого, о чем я все равно знаю, и обычно это не проблема.

В случаях, когда требуются более сложные лексикографические манипуляции с текстом, вам просто нужно использовать стороннюю библиотеку, такую ​​как Boost, что и следовало ожидать.

9
ответ дан Neutrino 23 August 2017 в 16:35
поделиться

См. std::lexicographical_compare :

// lexicographical_compare example
#include <iostream>  // std::cout, std::boolalpha
#include <algorithm>  // std::lexicographical_compare
#include <cctype>  // std::tolower

// a case-insensitive comparison function:
bool mycomp (char c1, char c2) {
    return std::tolower(c1)<std::tolower(c2);
}

int main () {
    char foo[] = "Apple";
    char bar[] = "apartment";

    std::cout << std::boolalpha;

    std::cout << "Comparing foo and bar lexicographically (foo < bar):\n";

    std::cout << "Using default comparison (operator<): ";
    std::cout << std::lexicographical_compare(foo, foo + 5, bar, bar + 9);
    std::cout << '\n';

    std::cout << "Using mycomp as comparison object: ";
    std::cout << std::lexicographical_compare(foo, foo + 5, bar, bar + 9, mycomp);
    std::cout << '\n';

    return 0;
}

Демо

7
ответ дан Brian Rodriguez 23 August 2017 в 16:35
поделиться

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

При тупом сравнении не будут найдены строки, которые могут быть одинаковыми, но не бинарными.

Пример:

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

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

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

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

52
ответ дан Coincoin 23 August 2017 в 16:35
поделиться
Другие вопросы по тегам:

Похожие вопросы: