C ++での大文字と小文字を区別しない文字列比較[終了]


373

文字列をすべて大文字またはすべて小文字に変換せずに、C ++で大文字と小文字を区別しない文字列比較を行う最良の方法は何ですか?

メソッドがUnicodeに対応しているかどうか、および移植性がどの程度かを示してください。


@ [Adam](#11679):このバリアントは使いやすさの点では優れていますが、不要なコピーを作成するため、パフォーマンスの点で悪いです。見落としがあるかもしれませんが、最良の(非Unicode)方法はを使用することstd::stricmpです。そうでなければ、ハーブが言っていることを読んでください。
Konrad Rudolph、

cでは通常、文字列全体を上に移動させてからその方法で比較するか、独自の比較をロールしました:P
マイケルドーガン

後の質問は単純な答えを持っています(少なくともBSD&POSIXコンパイラ用)strcasecmpはstackoverflow.com/questions/9182912/...
MOZ

@Mσᶎこの質問にもその答えがstrcasecmpあり、標準の一部ではなく、少なくとも1つの一般的なコンパイラーには欠けている重要な警告があります。
Mark Ransom、2014

回答:


317

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
}

14
これはUTF-8フレンドリーですか?私はそうは思いません。
vladr 2010年

18
いいえ、UTF-8では、アクセント、結合、bidiの問題などにより、同一の文字列を異なるバイナリコードでコード化できるため
vy32

10
@ vy32それは絶対に間違っています!UTF-8の組み合わせは相互に排他的です。常に可能な限り最短の表現を使用する必要があります。使用しない場合は、不正な形式のUTF-8シーケンスまたはコードポイントであるため、注意して処理する必要があります。
Wiz、

48
@Wiz、あなたはUnicode文字列の正規化の問題を無視しています。ñは、〜の後にnを続けたもの、またはñ文字で表すことができます。比較を実行する前に、Unicode文字列の正規化を使用する必要があります。Unicode Technical Report#15、 unicode.org
reports /

12
@wonkorealtime:大文字に変換された "ß"は "SS"であるため:fileformat.info/info/unicode/char/df/index.htm
Mooing Duck

118

標準を活用してくださいchar_traits。a std::stringは実際にはstd::basic_string<char>、またはより明示的にはのtypedefであることを思い出してくださいstd::basic_string<char, std::char_traits<char> >char_traitsタイプは、彼らはあなたがする必要があるのは、新しい文字列のtypedefであるなどをキャストする方法、彼らはどのようにコピーし、文字を比較する方法について説明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号に記載されています。


10
私自身の実験から知る限り、これにより新しい文字列型はstd :: stringと互換性がなくなります。
Zan Lynx 2012

8
もちろんそれはします-それ自体のために。大文字と小文字を区別しない文字列はtypedef std::basic_string<char, ci_char_traits<char> > istring、でなくtypedef std::basic_string<char, std::char_traits<char> > stringです。
Andreas Spindler、

232
「あなたがする必要があるすべて...」
Tim MB

3
@Nathanはおそらく、コードに対して基本的なCSEを実行できるコンパイラーを使用しています...
常磁性クロワッサン

17
この些細なケースでそのような狂気を強いるいかなる言語構成も後悔することなく放棄されるべきであり、放棄されることができます。
Erik Aronesty 2014年

86

ブーストの問題は、ブーストにリンクして依存する必要があることです。場合によっては簡単ではありません(例: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);
                      });
}

27
実際には、ブースト文字列ライブラリはヘッダーのみのライブラリであるため、何にもリンクする必要はありません。また、boostの 'bcp'ユーティリティを使用して、文字列ヘッダーのみをソースツリーにコピーできるため、完全なboostライブラリを必要とする必要はありません。
グレッチェン

ああ、私はbcpについて知らなかった、それは本当に便利そうだ。情報をありがとう!
Timmmm、2011年

9
シンプルでブーストに依存しないバージョンを知っておくと便利です。
Deqing 2014年

2
@Annaブーストのテキストライブラリを作成してリンクする必要があります。IBM ICUを使用します。
Behrouz.M、2015年

C ++ 11でも利用可能
火星

58

POSIXシステムを使用している場合は、strcasecmpを使用できます。ただし、この関数は標準Cの一部ではなく、Windowsでも使用できません。これは、ロケールがPOSIXである限り、8ビット文字に対して大文字と小文字を区別しない比較を実行します。ロケールがPOSIXでない場合、結果は未定義です(ローカライズされた比較が行われる場合と行われない場合があります)。同等のワイド文字は使用できません。

これに失敗すると、多くの歴史的なCライブラリの実装に関数stricmp()とstrnicmp()があります。Windows上のVisual C ++は、ANSI標準の一部ではないため、アンダースコアを前に付けることにより、これらすべての名前を変更しました。そのため、そのシステムでは、これらは_stricmpまたは_strnicmpと呼ばれます。一部のライブラリには、ワイド文字またはマルチバイトの同等の関数(通常、wcsicmp、mbcsicmpなどの名前が付いている)も含まれている場合があります。

CとC ++はどちらも国際化の問題をほとんど認識していないため、サードパーティのライブラリを使用することを除いて、この問題に対する適切な解決策はありません。IBM ICU(International Components for Unicode)を調べてください。C / C ++の堅牢なライブラリが必要な場合は、。ICUは、WindowsシステムとUnixシステムの両方に対応しています。


53

ばかげた大文字と小文字を区別しない比較または完全に正規化されたUnicode比較について話しているのですか?

単純な比較では、同じである可能性はあるがバイナリが等しくない文字列は検出されません。

例:

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

すべて同等ですが、バイナリ表現も異なります。

とはいえ、特にハングル、タイ語、およびその他のアジア言語をサポートする予定の場合は、Unicodeの正規化を必ずお読みください。

また、IBMはほとんどの最適化されたUnicodeアルゴリズムの特許を取得し、それらを一般に公開しました。彼らは実装も維持しています:IBM ICU



31

boost :: iequalsは、文字列の場合、utf-8互換ではありません。boost :: localeを使用できます

comparator<char,collator_base::secondary> cmpr;
cout << (cmpr(str1, str2) ? "str1 < str2" : "str1 >= str2") << endl;
  • プライマリ-基本文字のみを比較して、アクセントと大文字小文字を無視します。たとえば、「ファサード」と「ファサード」は同じです。
  • 二次-文字の大文字小文字を無視しますが、アクセントを考慮します。「ファサード」と「ファサード」は異なりますが、「ファサード」と「ファサード」は同じです。
  • 三次-大文字小文字の区別とアクセントの両方を考慮します。「ファサード」と「ファサード」は異なります。句読点を無視します。
  • 第四紀-すべての大文字小文字、アクセント、句読点を考慮します。単語は、Unicode表現に関して同一である必要があります。
  • 同一-4項と同じですが、コードポイントも比較します。

30

非Unicodeバージョンについて最初に考えたのは、次のようなことです。


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;
}

20

strcasecmpUnixまたはstricmpWindowsで使用できます。

これまで言及されていないことの1つは、これらのメソッドでstl文字列を使用している場合、最初に2つの文字列の長さを比較すると便利です。この情報は文字列クラスですでに利用できるためです。これにより、比較する2つの文字列がそもそも同じ長さでない場合に、コストのかかる文字列比較を実行できなくなる可能性があります。


文字列の長さを決定することは、文字列内のすべての文字を反復し、それを0と比較することで構成されるので、それと実際に文字列をすぐに比較することとの間に、それほど大きな違いがありますか?両方の文字列が一致しない場合はメモリの局所性が向上すると思いますが、一致する場合はおそらくランタイムが2倍近くなります。
公証人2014年

3
C ++ 11は、std :: string :: lengthの複雑さは一定でなければならないことを指定しています:cplusplus.com/reference/string/string/length
bradtgmurray

1
それは楽しい小さな事実ですが、ここではほとんど関係がありません。strcasecmp()とstricmp()はどちらも装飾されていないC文字列をとるため、std :: stringは関係しません。
uliwitness 2014

3
「a」と「ab」を比較すると、これらのメソッドは-1を返します。長さが異なりますが、「a」は「ab」の前にあります。したがって、呼び出し側が順序付けを気にする場合は、単に長さを比較することはできません。
ネイサン14


13

私はすべての投稿から良い答えをまとめようとしていますので、これを編集してください:

これはこれを行う方法ですが、文字列を変換し、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()は実際にはstdライブラリの一部ではなく、ほとんどのコンパイラベンダーによってのみ実装されているため、これはstricmp()よりも移植性があります。

本当にUnicodeフレンドリーな実装を得るには、stdライブラリの外に出なければならないようです。良いサードパーティライブラリの1つは IBM ICU(International Components for Unicode)です。

また、boost :: iequalsは、この種の比較を行うためのかなり優れたユーティリティを提供します。


教えてください、:: tolowerの意味、tolower()の代わりにtolowerを使用できる理由、および以前の「::」とは何ですか?ありがとう
VextoR

17
これは非常に効率的なソリューションではありません。両方の文字列のコピーを作成し、最初の文字が異なっていてもすべてを変換します。
Timmmm、2011年

2
とにかくコピーを作成する場合は、参照ではなく値で渡してみませんか?
celticminstrel 2015年

ブーストなしのシンプルなヒントだと思います。:)
cmcromance 2016年

1
質問はtransform、比較前に文字列全体ではないことを明示的に要求します
Sandburg

12
str1.size() == str2.size() && std::equal(str1.begin(), str1.end(), str2.begin(), [](auto a, auto b){return std::tolower(a)==std::tolower(b);})

ブーストを使用する立場にない場合は、C ++ 14で上記のコードを使用できます。std::towlowerワイド文字を使用する必要があります。


4
str1.size() == str2.size() &&str2がstr1のプレフィックスであるときに範囲外にならないように、前にaを追加する必要があると思います。
ɲeuroburɳ

11

Boost.Stringライブラリーでは、大文字insenstive比較を行うために、オンようなアルゴリズムをたくさん持っています。

独自に実装することもできますが、それが既に行われているのになぜ煩わしいのでしょうか。


1
std :: stringに組み込みの方法はありませんか?
WilliamKF 2010年

6
いいえ、ありません。
ディーンハーディング

3
「……それがすでに行われているのに、なぜわざわざ?」-Boostを使用していない場合はどうなりますか?OPには質問のタグがありませんでした。
jww 2016

11

FYI、strcmp()stricmp()彼らはヌルターミネータを打つまで、彼らはただ処理するので、バッファオーバーフローの脆弱です。_strncmp()and を使用する方が安全_strnicmp()です。


6
True、ただし、バッファーのオーバーリードは、バッファーのオーバーライトよりもはるかに危険性が低くなります。
Adam Rosenfield、

4
stricmp()およびstrnicmp()POSIX標準の一部ではありません:-(しかし、あなたは見つけることができるstrcasecmp()strcasecmp_l()strncasecmp()およびstrncasecmp_l()POSIXヘッダにstrings.h:-)参照opengroup.orgを
olibre

2
@AdamRosenfield「より悪い」はコンテキストに依存します。セキュリティ上、上書きの全体的なポイントは、オーバーリードすることです。
karmakaze 2015年

10

を参照してください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;
}

デモ


1
この方法は、潜在的に安全でなく、移植できません。std::tolower文字がASCIIエンコードされている場合にのみ機能します。そのような保証はありませんstd::string-そのため、未定義の動作になる可能性があります。
プラズマセル2018年

@plasmacel次に、他のエンコーディングと連動する関数を使用します。
ブライアンロドリゲス

9

基本的な大文字と小文字を区別しない文字列比較の必要性については、外部ライブラリを使用する必要がないことを好みます。また、他のすべての文字列と互換性のない大文字と小文字を区別しない特性を持つ個別の文字列クラスを必要としません。

だから私が思いついたのはこれです:

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のようなサードパーティのライブラリを使用する必要がありますが、これは期待されています。


2
テンプレートにして、個別のstring / wstringバージョンの代わりにbasic_string <T>を使用した場合、おそらくその1つの関数を作成できますか?
公証人2014年

2
単一の関数テンプレートが特殊化やマクロを使用せずにtoupperまたはtowupperを呼び出す方法では、関数のオーバーロードはどちらよりも単純で適切な実装のように見えます。
ニュートリノ

9

短くて素敵です。拡張 std C lib 以外の依存関係はありません。

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

とが等しい場合にtrueを返します。 類似があるかもしれない、存在しないかもしれない、など、str1str2strcasecmpstricmpstrcmpi

コード例:

#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

6
C ++ではstdという奇妙ではありません::文字列には比較方法-ケースを無視している...
KYB

1
「strcasecmpは標準の一部ではありません」-Mark Ransom Dec 1 '14 at 19:57
Liviu

はい、しかし、ほとんどの現代のコンパイラはそれまたは別の名前のアナログを持っています。stricmpstrcmpistrcasecmp、などありがとうございます。メッセージを編集しました。
kyb

TODO:ストリーム用にブール値を文字に暗黙的に変換するためcout << boolalpha、myではなく使用bool2strします。
kyb 2017年

これは、gccのライブラリの<strings.h>にあります。
フクロウ

7

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

すでに存在する魔法の関数ではなくメソッドを探しているとすると、率直に言ってこれ以上の方法はありません。限られた文字セット用の巧妙なトリックを使用してコードスニペットを作成することはできますが、結局のところ、ある時点で文字を変換する必要があります。

この変換の最善の方法は、比較の前に行うことです。これにより、実際の比較演算子が無視されるべきであるエンコードスキームに関して、かなりの柔軟性が得られます。

もちろん、この変換を独自の文字列関数またはクラスの背後に「隠す」ことができますが、比較する前に文字列を変換する必要があります。


6

組み込みのstd :: basic_stringメンバー関数を使用して比較や検索などを行うときに大文字と小文字を区別しないstd :: stringを生成するために、std :: basic_stringで使用するchar_traitsの大文字と小文字を区別しないバージョンを作成しました。

つまり、こういうことをやりたかったんです。

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;

2
これは通常の文字では機能しますが、すべてのUnicodeでは機能しません。大文字と小文字の区別が必ずしも双方向ではないためです(ギリシャ語には、シグマを含む良い例があります。今は覚えられません。小文字が2つと大文字が1つあるようなものです) 、どちらの方法でも適切な比較を行うことはできません)
coppro '24年

1
それは実際にそれを行うには間違った方法です。大文字と小文字の区別は、文字列自体のプロパティであってはなりません。同じ文字列オブジェクトで大文字と小文字を区別する比較と区別しない比較の両方が必要な場合はどうなりますか?
Ferruccio

大文字と小文字の区別が文字列の「一部」であることが適切でない場合、find()関数もまったく同じではありません。あなたにとって、それは本当かもしれません、そしてそれは結構です。C ++のIMOの最大の特徴は、プログラマに特定のパラダイムを強制しないことです。それはあなたが望む/必要とするものです。
John Dibling

実際、ほとんどのC ++グル(標準委員会のものと同様)は、find()をstd :: basic_string <>に配置するのは間違いなく、同じように配置できる他の多くのものと一緒になっていると思います無料の機能。その上、それを型に入れることにはいくつかの問題があります。
Andreas Magnusson

他の人が指摘したように、このソリューションには2つの大きな問題があります(皮肉なことに、1つはインターフェースであり、もう1つは実装です;-))。
Konrad Rudolph

4

International Components for Unicodeライブラリの使用経験は豊富です。これらは非常に強力であり、変換、ロケールのサポート、日付と時刻のレンダリング、大文字小文字のマッピング(必要ではないようです)、および照合のメソッドを提供します。これには、大文字と小文字およびアクセントを区別しない比較(およびその他)が含まれます。私はライブラリのC ++バージョンのみを使用しましたが、Javaバージョンもあるようです。

@Coincoinによって参照される正規化された比較を実行するメソッドが存在し、ロケールを説明することもできます-たとえば(これは厳密な等価ではなく、ソートの例です)、伝統的にスペイン語(スペイン)では、文字の組み合わせ「ll」は"l"と "m"なので、 "lz" <"ll" <"ma"。


4

大文字と小文字を区別する場合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の前に来るので、リンゴはボールの前に来ます


2
これはC ++の方法ではほとんどないため、反対票を投じます。
Thomas Daugaard 2013

これは私の大学でのC ++の慣例ですが、ここに投稿するときは覚えておきます
reubenjohn

4
stricmpは、Microsoftの拡張機能であるAFAIKです。BSDは代わりにstrcasecmp()を持っているようです。
公証人2014年

3

パーティーには遅れますが、これはを使用するバリアントであり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

最終的に選択した方法についてのメモです。もしその方法が偶然に strcmpいくつかの回答の、します。

strcmp一般的にUnicodeデータでは機能しません。一般に、strcmpバイトごとの比較とutf-8でエンコードされたUnicodeコードポイントは1バイト以上しか使用できないため、utf-8 などのバイトベースのUnicodeエンコーディングでも機能しません。strcmp適切に処理される唯一の特定のUnicodeケースは、バイトベースのエンコーディングでエンコードされた文字列にU + 00FF未満のコードポイントのみが含まれる場合であり、バイトごとの比較で十分です。


2

2013年の初めの時点で、IBMが管理しているICUプロジェクトは、これに対するかなり良い答えです。

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

ICUは、「業界標準を厳密に追跡する完全なポータブルUnicodeライブラリ」です。文字列比較の特定の問題については、Collat​​ionオブジェクトが必要な処理を実行します。

Mozillaプロジェクトは、2012年半ばにFirefoxの国際化にICUを採用しました。ここでは、ビルドシステムの問題やデータファイルのサイズなど、エンジニアリングに関する議論を追跡できます。


2

上記の解決策は比較方法を使用しておらず、合計を再度実装していないようです。ここに私の解決策を示します。うまくいくことを願っています(正常に機能しています)。

#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;
}

1

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;
}

std :: toupperは#include <cctype>にあると思うので、含める必要があるかもしれません。
デビッドレジャー

この:: toupperのようなグローバルバージョンを使用する場合、ロケールが異なるバージョンのcバージョンとc ++バージョンの2つがあるため、<ctype>を含める必要がない場合があります。グローバルバージョン "::
toupper

文字列の1つが空の場合、このソリューションは失敗します: ""
-false

0

ソース文字列を他の文字列とより頻繁に比較する必要がある場合、1つのエレガントな解決策は正規表現を使用することです。

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

std::wregex pattern(first, std::wregex::icase);
bool isEqual = std::regex_match(second, pattern);

これを試してみたがコンパイルエラー: error: conversion from 'const char [5]' to non-scalar type 'std::wstring {aka std::basic_string<wchar_t>}' requested
Deqing

悪いアイデア。最悪の解決策です。
Behrouz.M、2015年

これは良い解決策ではありませんが、使用する場合でも、ワイドストリング定数の前にLが必要です(例:L "TEST"
celticminstrel

誰かがそれが最悪の解決策である理由を誰かが説明できたらいいのに。パフォーマンスの問題のため?正規表現の作成にはコストがかかりますが、その後の比較は非常に高速になります。
smibe 2015

使いやすく移植性があります。主な問題は、最初に正規表現が使用する文字を含めることができないことです。そのため、一般的な文字列比較としては使用できません。また、速度も遅くなります。smibeが言うように機能させるためのフラグがありますが、それでも一般的な関数としては使用できません。
ベン

0

c ++(Windowsでテスト済み)で2つの文字列を比較する簡単な方法は、_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をご覧ください。


この回答に加えて、a)C関数であり、b)おそらく移植できないため、stackoverflow.com / a / 12414441/95309を読む価値があります。
クラウス・ヨルゲンセン

これを機能させるために必要な#includeは何ですか?
ekkis

1
:あなたはここで読むことができますように、<string.hの>含める必要はあり_stricmp使用する@ekkis docs.microsoft.com/en-us/cpp/c-runtime-library/reference/...を
Dameの

-1
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;
        }
      }
}

これはおそらくはるかに効率的にすることができますが、ここにすべてのビットが裸のかさばるバージョンがあります。

それほどポータブルではありませんが、私のコンピュータにあるものなら何でもうまく機能します(わからない、私は言葉ではなく写真です)


これはUnicodeのサポートではないため、質問の対象となります。
Behrouz.M、2015年

これは、英語以外の文字セットをサポートしていません。
Robert Andrzejuk

-3

小文字と大文字のみが異なる文字列を比較する簡単な方法は、ASCII比較を行うことです。すべての大文字と小文字はASCIIテーブルで32ビット異なります。この情報を使用すると、次のようになります...

    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
これによれば、「++ j」は「KKJ」と等しく、「1234」は「QRST」と等しくなります。それは誰もが望んでいることだと思います。
celticminstrel 2015年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.