条項35:mismatchまたはlexicographical比較による単純な大文字と小文字の無関係文字列比較


あるSTL菜鳥が最もよく聞く質問は「STLを使って大文字と小文字の関係のない文字列の比較をする方法」です.これは人を惑わす簡単な問題だ.大文字と小文字に関係のない文字列の比較は本当に簡単か本当に難しいか、あなたがこの問題をどのように解決するかに依存します.国際化の問題を無視し、文字列strcmpのようなタイプに設計することに注目すれば、このタスクは簡単です.strcmpが持たない文字列の文字を言語で処理する能力(つまり、テキストを収容する文字列は英語以外の言語)やプログラムがデフォルトではなくlocaleを使用する場合は、このタスクは困難です.
この条項では、STLがどのようにタスクを完了するかを示すのに十分な簡単なバージョンを作成します.(この問題は、比較的難しいバージョンでもSTLで解決できます.正確には、付録Aで見られるlocaleに関する問題を解決します.)簡単な問題をより困難にするために、2回処理します.大文字と小文字の比較に関係のないプログラマーを使用するには、strcmpのような2つの異なる呼び出しインタフェースが必要です.(負の数、ゼロ、または正の数を返します)とoperator(trueまたはfalseを返します)のようなものを返します.したがって、STLアルゴリズムを使用して2つの呼び出しインタフェースを実装する方法を説明します.
しかし、まず、2つの文字が大文字と小文字を除いて等しいかどうかを決定する方法が必要です.国際化の問題を考慮する必要がある場合、これは複雑な問題です.次の文字比較は明らかに簡単すぎる解決策ですが、strcmpのような文字列比較です.この条項ではstrcmpのような文字列比較だけを考慮し、国際化の問題を考慮しないので、この関数で十分です.
int ciCharCompare(char c1, char c2)   //          
{      // c1 c2,  c1 < c2  -1,
      //   c1==c2  0,  c1 > c2  1
 int Ic1 = tolower(static_cast(c1));//        
 int Ic2 = tolower(static_cast(c2));//    
 if (Ic1 < Ic2) return -1;
 if (lc1 > Ic2) return 1;
 return 0;
}

この関数はstrcmpに従い,c 1とc 2の関係に依存する負の数,ゼロまたは正の数を返すことができる.strcmpとは異なり,ciCharCompareは比較前に2つのパラメータを小文字に変換する.これにより、大文字と小文字に関係のない文字比較が生成されます.
(それも)の多くの関数のように、tolowerのパラメータと戻り値のタイプはintですが、このintがEOFでない限り、その値はunsigned charとして表現されなければなりません.CとC++では、charはシンボルではないかもしれません.(実装に依存)charにシンボルがある場合、その値がunsigned charとしてのみ表現できることを確認する方法は、tolowerを呼び出す前に変換することです.これは、上記のコードの変換を説明します.(charがシンボルなしの実装では、この変換は機能しません.)これは、charではなくintを保存することを説明します.
ciCharCompareが与えられると,strcmpのようなインタフェースを提供する最初の大文字と小文字に関係のない2つの文字列比較関数を簡単に書くことができる.ciStringCompareという関数は、比較する文字列の関係に依存する負の数、ゼロ、または正の数を返します.それはmismatchアルゴリズムに基づいている.mismatchは2つの区間の最初の対応する異なる値の位置を決定するからである.
mismatchを呼び出す前に、その前提を満たさなければなりません.特に,ある文字列が他の文字列より短く,短い文字列が最初の区間として伝達されるかどうかを決定しなければならない.したがって、ciStringCompareImplという関数に本格的な作業を行い、ciStringCompareに伝達されたパラメータの順序が正しいことを簡単に確保し、パラメータが交換されたら戻り値を調整することができます.
int ciStringCompareImpl(const string& s1,  //       
   const string& s2);
int ciStringCompare(const string& s1, const string& s2)
{
 if (s1.size() <= s2.size()) return ciStringCompareImpl(s1, s2);
 else return -ciStringCompareImpl(s2, s1);
}

ciStringCompareImplでは、ほとんどの作業がmismatchで完了します.区間の最初の対応する文字の異なる位置を示す一対の反復器を返します.
int ciStringCompareImpl(const string& si, const strings s2)
{
 typedef pair<:const_iterator psci="“pair" of="" string::const_iterator=""> PSCI; // string::const_iterator”
 PSCI p = mismatch(     //      
   s1.begin(), s1.end(),  //      
   s2.begin(),   //   not2;  
   not2(ptr_fun(ciCharCompare))); //   41      
       //     ptr_fun
 if (p.first== s1.end()) {    //     ,s1  
  if (p.second == s2.end()) return 0;  // s2 s1 s2 
  else return -1;
 }
 return ciCharCompare(*p.first, *p.second);  //         
}       //          

幸いなことに、注釈はすべてのものを明らかにしました.基本的には、文字列の最初の異なる文字の位置を知ると、どの文字列があるかを簡単に決定することができます.もしあれば、別の前にあります.唯一不思議に思うのはmismatchに伝わる判断式、すなわちnot 2(ptr_fun(ciCharCompare))である.文字が一致すると、この判断式はtrueを返します.判断式がfalseを返すとmismatchが停止するからです.-1、1、または0を返し、文字が一致するとstrcmpのように0を返すため、ciCharCompareを使用することはできません.もし私たちがciCharCompareを判断式としてmismatchに伝えると、C++はciCharCompareの戻りタイプをboolに変換しますが、もちろんboolの中でゼロの等価物はfalseで、ちょうど私たちが望んでいるのとは反対です!同様に、ciCharCompareが1または–1を返すと、Cのようにすべての非ゼロ整数値がtrueと見なされるため、trueとして解釈される.これは再び私たちが望んでいるのとは反対です.この意味の逆転を修正するには、ciCharCompareの前にnot 2とptrを置きます.fun、そして私たちはずっと楽しく生活します.
我々の第2の方法ciStringCompareは適切なSTL判定式を生成することである:関連容器で比較関数の関数として使用することができる.この実装は短くて良いです.ciCharCompareを判断インタフェースのある文字比較関数に変更し、文字列比較を行う作業をSTLの名前の2番目に長いアルゴリズムであるlexicographical_に渡す必要があるからです.compare:
bool ciCharLess(char c1, char c2)    //         
{        //     c1  
        //  c2  ;
 tolower(static_cast(c1)) <   //   46      
  tolower(static_cast(c2)); //         
}        //     
bool ciStringCompare(const string& s1, const string& s2)
{
 return lexicographical_compare(s1.begin(), s1.end(),  //     
     s2.begin(), s2.end(), //      
     ciCharLess);  //      
}

いいえ、私はあなたにこれ以上心配させません.名前が一番長いアルゴリズムはset_symmetric_difference.
lexicographicalに詳しいならcompareの動作は、上のコードがはっきりしています.もしあなたがいなければ、コンクリートを隔てているように見えるかもしれません.幸いなことに、コンクリートをガラスに変えるのは難しくありません.
lexicographical_compareはstrcmpの汎用バージョンです.strcmpは文字配列にのみ機能しますがlexicographical_compareは、すべてのタイプの値の区間に役立ちます.同時に、strcmpは常に2つの文字を比較して、それらの関係が等しいか、小さいか、または他の文字より大きいかを見てみましょう.lexicographical_compareは、2つの値が1つのユーザ定義基準を満たすかどうかを決定する2元判定式を入力することができる.
上の呼び出しでlexicographical_compareは、ciCharLessを呼び出した結果に基づいて、s 1とs 2の最初の異なる位置を探すために使用される.もし、その位置の文字を使うならば、ciCharLessはtrueを返して、lexicographical_compareも;1番目の文字が異なる場所で、1番目の文字列からの文字が2番目の文字列からの文字より先に、1番目の文字列が2番目に先に来た場合.strcmpのようにlexicographicalcompareは、2つの等しい値の区間が等しいと考えているので、このような2つの区間についてfalseを返します.1つ目の区間は2つ目の前ではありません.strcmpのように、最初の区間が異なる対応値を発見する前に終了した場合、lexicographical_compareはtrueを返します.任意の区間より先に接頭辞が接頭辞です.
mismatchとlexicographicalについてたくさん話しました.compare.本書の軽量性に焦点を当てていますが、標準Cライブラリへの非標準拡張として、大文字と小文字に関係のない文字列比較関数が広く存在することに言及しなかったら、私は職務怠慢かもしれません.一般的にstricmpやstrcmpiという名前があり、本条項で開発した関数と同様に国際化のサポートを提供していません.移植性を犠牲にしたい場合は、文字列に埋め込まれたnullが含まれていないことを知っています.国際化に関心を持っていない場合は、大文字と小文字に関係のない文字列を実現する最も簡単な方法を見つけることができます.STLはまったく異なります.代わりに、2つの文字列をconst char*ポインタに変換し(条項16を参照)、ポインタにstricmpまたはstrcmpiを使用します.
int ciStringCompare(const string& s1, const string& s2)
{
 return stricmp(s1.c_str(),s2.c_str());   //       
}        //      
        //   stricmp

これをhackと呼ぶ人もいるかもしれませんが、stricmp/strcmpiは1つのことだけをするように最適化され、長い文字列に対して一般的に汎用アルゴリズムmismatchやlexicographicalよりも実行されます.compareはずっと速いです.もしそれがあなたにとって重要であれば、あなたが非標準C関数で標準STLアルゴリズムを完成することを気にしないかもしれません.STLを最も効率的に使用する方法は、他の方法がより良いことを認識することである.
 
海南黄花梨、ベトナム黄花梨、草花梨、小葉紫檀、黒檀、香紫檀、緑檀、黄楊木、桃木、漆芸髪かんざし木櫛樟木壁掛仏珠車飾
贈り物の佳品をコレクションして、注文することもできます
淘宝店:http://shop36570193.taobao.com撮影店:http://421840135.paipai.com/
連絡先:QQ 421840135旺xiaobaitucslメール[email protected]
本文はCSDNブログから来て、転載して出典を明記してください:http://blog.csdn.net/dengjiang1999/archive/2009/06/24/4294240.aspx