2011-01-23 7 views
12

std::stringを比較する最良の方法は何ですか?明白な方法はif/elseで次のようになります。std :: stringsを比較する最良の方法

std::string input; 
std::cin >> input; 

if (input == "blahblahblah") 
{ 
    // do something. 
} 

else if (input == "blahblah") 
{ 
    // do something else. 
} 

else if (input == "blah") 
{ 
    // do something else yet. 
} 

// etc. etc. etc. 

別の可能性はstd::mapswitch/caseを使用することです。これらの比較のロット(8,10,12 +など)を行うときの最良の方法は何ですか?

+1

ええ、文字列のマップを使用するだけで機能します。 – Ben

+0

@Benあなたは答えとして例を投稿できますか? –

答えて

25

ここでは、std :: mapを使用した例を示します。

#include <map> 
#include <string> 
#include <iostream> 
#include <utility> 

void first() 
{ 
    std::cout << "first\n"; 
} 

void second() 
{ 
    std::cout << "second\n"; 
} 

void third() 
{ 
    std::cout << "third\n"; 
} 


int main() 
{ 
    typedef void(*StringFunc)(); 
    std::map<std::string, StringFunc> stringToFuncMap; 

    stringToFuncMap.insert(std::make_pair("blah", &first)); 
    stringToFuncMap.insert(std::make_pair("blahblah", &second)); 
    stringToFuncMap.insert(std::make_pair("blahblahblah", &third)); 

    stringToFuncMap["blahblah"](); 
    stringToFuncMap["blahblahblah"](); 
    stringToFuncMap["blah"](); 
} 

出力は次のとおりです。

second 
third 
first 

このアプローチの利点は以下のとおりです。

  • それは簡単に拡張です。
  • これは、文字列処理ルーチンを別々の関数に分割することを強制します(意図によるプログラミング)。あなたの例では、O(n)の

ブーストを使用して::機能を特にクラスのメンバ関数で、構文は少しよりよい作ることに見ているのに対し、

  • 機能ルックアップは、(n個のログ)Oです。

  • +1

    これは良いようです。しかし、なぜstringToFuncMap ["blah"] =&first'の代わりに 'stringToFuncMap.insert(std :: make_pair(" blah "、&first)); –

    +1

    operator []はマップを初期化するために正常に動作します。私はちょうど挿入メソッドでマップを初期化するために使用されています。演算子[]は、最初に "second"のデフォルトを初期化してstd :: pairを作成するので、少し効率的です。私はMeyersの「Effective STL」がこれを深くカバーしていると思います。 – Ben

    +0

    大丈夫、知っておいてよかったです。 –

    1

    「12」は大したことではありませんが、とにかくです。それがstd::stringのために問題外ですので

    あなただけの、整数型(charint、など)のためのswitchを使用することができます。おそらくマップを使用する方が読みやすくなります。

    もう一度、それはあなたが "ベスト"をどのように定義するかによって異なります。

    +0

    ハッシュ( "foo")がconstexprになるように、C++ 0xを修正しましたか?その後、文字列のハッシュをオンにすることができます。 – KitsuneYMG

    +1

    @KitsuneYMGでも、衝突があったらどうしますか?同じ値を持つ複数のラベルになります。私はハッシュ値がスイッチのための良いラベルを作るとは思わない。 –

    +0

    @EtiennedeMartelそのための 'static_assert'または' assert'でチェックすることができます。 – user1095108

    3

    operator==を使用するとかなり良いですが、パフォーマンスが非常に重要な場合は、使用状況に応じて改善することができます。いくつかの選択肢の中から1つを選択して特定のアクションを実行することが目標の場合は、TRIEを使用できます。

    switch(s[0]) { 
    case 'a': 
        // only compare to strings which start with an 'a' 
        if(s == "abcd") { 
    
        } else if (s == "abcde") { 
    
        } 
        break; 
    case 'b': 
        // only compare to strings which start with an 'b' 
        if(s == "bcd") { 
    
        } else if (s == "bcde") { 
    
        } 
        break; 
    default: 
        // we know right away it doesn't match any of the above 4 choices... 
    } 
    

    基本的にすべての文字列が中に少なくともNである場合、最初にする必要はありません良いユニークさ(文字列内の特定の文字を使用します。文字列が十分に異なっている場合にも、あなたがこのような何かを行うことができますNを実行する前に任意の長さの文字列)を入力してswitchを実行し、その固有の特性に一致する文字列のサブセットに対して一連の比較を実行します。

    0

    この質問に対する回答はすべてこの問題に依存します。あなたは2つの例を挙げました。ハッシュテーブル、正規表現などのオプションを追加することができます。

    0

    8、10、および12の比較でも、if ... else if ...スキームを使用できますが、何も悪いことはありません。あなたは100何かをしたい場合は、文字列のハッシュを計算する関数を書くことをお勧めしたい(すべての文字を単純にxoringすることによっても、より良い配布のためには他の良い方法が望ましいだろう)、そしてその結果をEvan提案された。関数がすべての可能な入力文字列に対して一意の数値を返す場合、それはさらに優れており、追加の比較を必要としません。

    0

    「最高の人」が「最も効率的」を意味する場合は、先にお読みください。

    本当にたくさんある場合は、次の方法を使用することをお勧めします。スイッチで
    文字列は何かが(Project Coinの一部として)は、Java 7になります実際にある

    そしてproposalによると、これは、Java言語がそれを実装する方法です。
    まず、各文字列のハッシュ値を計算する。この問題は、現在のほとんどの言語で利用可能な「スイッチint」の問題であり、効率的です。 case文のそれぞれで、これが実際に文字列かどうかを確認します(まれに、異なる文字列が同じintにハッシュする可能性があります)。
    私は個人的には、特定のプログラムがある状況、つまり可能な文字列がプログラマーの制御下にあるかどうか、プログラムがどれほど堅牢である必要があるかによって、実際には最後のステップを実行しないことがあります。

    サンプル擬似コードに対応the fore-mentioned proposalから

    String s = ... 
    switch(s) { 
    case "quux": 
        processQuux(s); 
        // fall-through 
    
        case "foo": 
        case "bar": 
        processFooOrBar(s); 
        break; 
    
        case "baz": 
        processBaz(s); 
        // fall-through 
    
        default: 
        processDefault(s); 
        break; 
    } 
    

    はあなたが理解するのに役立ちます。

    // Advanced example 
    { // new scope for synthetic variables 
        boolean $take_default = false; 
        boolean $fallthrough = false; 
        $default_label: { 
         switch(s.hashCode()) { // cause NPE if s is null 
         case 3482567: // "quux".hashCode() 
          if (!s.equals("quux")) { 
           $take_default = true; 
           break $default_label; 
          } 
          processQuux(s); 
          $fallthrough = true; 
           case 101574: // "foo".hashCode() 
          if (!$fallthrough && !s.equals("foo")) { 
           $take_default = true; 
           break $default_label; 
          } 
          $fallthrough = true; 
         case 97299: // "bar".hashCode() 
          if (!$fallthrough && !s.equals("bar")) { 
           $take_default = true; 
           break $default_label; 
          } 
          processFooOrBar(s); 
          break; 
    
         case 97307: // "baz".hashCode() 
          if (!s.equals("baz")) { 
           $take_default = true; 
           break $default_label; 
          } 
          processBaz(s); 
          $fallthrough = true; 
    
         default: 
          $take_default = true; 
          break $default_label; 
         } 
        } 
        if($take_default) 
         processDefault(s); 
    } 
    
    +0

    質問はC++(std :: string)のためでした:) – Tiago

    関連する問題