2011-01-23 31 views
12

Cách tốt nhất để so sánh std::string là gì? Cách hiển nhiên sẽ là với if/else:Cách tốt nhất để so sánh 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. 

Một khả năng khác là sử dụng một std::mapswitch/case. Cách tốt nhất khi thực hiện rất nhiều (như 8, 10, 12+) của những so sánh này?

+1

Vâng, chỉ cần sử dụng bản đồ từ chuỗi này đến hàm khác. – Ben

+0

@Ben bạn có thể đăng một ví dụ làm câu trả lời không? –

Trả lời

25

Đây là ví dụ sử dụng 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"](); 
} 

Output là:

second 
third 
first 

Những lợi ích của phương pháp này là:

  • Đó là một cách dễ dàng mở rộng.
  • Nó buộc bạn phải thoát ra các thói quen xử lý chuỗi thành các chức năng riêng biệt (lập trình theo ý định).
  • Chức năng tra cứu là O (log n), trong khi ví dụ của bạn là O (n)

Nhìn vào sử dụng tăng :: chức năng để thực hiện cú pháp một chút đẹp hơn, đặc biệt với chức năng thành viên lớp.

+1

điều này có vẻ tốt. nhưng một câu hỏi, tại sao bạn làm 'stringToFuncMap.insert (std :: make_pair (" blah ", & đầu tiên));' thay vì 'stringToFuncMap [" blah "] = & first'? –

+1

toán tử [] sẽ hoạt động tốt để khởi tạo bản đồ. Tôi chỉ được sử dụng để khởi tạo một bản đồ với phương thức chèn. Nó hiệu quả hơn, vì toán tử [] trước tiên sẽ tạo một cặp :: std với giá trị mặc định "thứ hai" được khởi tạo. Tôi nghĩ rằng "STL hiệu quả" của Meyers bao hàm điều này theo chiều sâu. – Ben

+0

Được rồi, tốt để biết. –

1

"12" không nhiều ... nhưng dù sao đi nữa.

Bạn chỉ có thể sử dụng switch cho các loại tích phân (char, int, v.v.), do đó, đó là câu hỏi cho std::string. Sử dụng bản đồ có thể dễ đọc hơn.

Sau đó, một lần nữa, tất cả phụ thuộc vào cách bạn xác định "tốt nhất".

+0

Họ đã từng sửa C++ 0x sao cho băm ("foo") là một constexpr? Sau đó bạn có thể bật băm của chuỗi. – KitsuneYMG

+1

@KitsuneYMG Thậm chí sau đó, nếu có va chạm thì sao? Bạn sẽ kết thúc với nhiều nhãn có cùng giá trị. Tôi không nghĩ rằng một giá trị băm sẽ làm cho một nhãn hiệu tốt cho một chuyển đổi. –

+0

@EtiennedeMartel Bạn có thể kiểm tra bằng 'static_assert' hoặc' assert' cho điều đó. – user1095108

3

sử dụng operator== là khá tốt, nhưng nếu hiệu suất thực sự quan trọng, bạn có thể cải thiện tùy thuộc vào trường hợp sử dụng của bạn. Nếu mục tiêu là chọn một trong một vài lựa chọn và thực hiện một hành động cụ thể, bạn có thể sử dụng một số TRIE. Ngoài ra nếu các dây đủ khác nhau, bạn có thể làm một cái gì đó như thế này:

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

cơ bản sử dụng một nhân vật nào đó trong chuỗi mà tốt tính độc đáo (không nhất thiết phải là người đầu tiên nếu tất cả các chuỗi ít nhất N trong chiều dài bất kỳ ký tự nào trước N sẽ làm!) để thực hiện switch sau đó thực hiện một loạt các so sánh trên một tập hợp con của các chuỗi phù hợp với đặc tính duy nhất đó.

0

Câu trả lời cho câu hỏi này là quá phụ thuộc vào vấn đề. Bạn đã đặt tên cho hai ví dụ. Bạn có thể thêm vào tùy chọn của mình những thứ như bảng băm, cụm từ thông dụng, v.v.

0

Với 8, 10 và thậm chí 12 so sánh bạn vẫn có thể sử dụng sơ đồ if ... else if ..., không có gì xấu. Nếu bạn muốn 100 hoặc cái gì đó, tôi khuyên bạn nên viết một hàm sẽ tính toán băm của chuỗi (thậm chí bằng cách xén tất cả ký tự đơn giản, nhưng một số phương pháp tốt khác sẽ thích hợp hơn để phân phối tốt hơn) và sau đó chuyển qua kết quả là Evan đề xuất. Nếu hàm trả về các số duy nhất cho tất cả các chuỗi đầu vào có thể - thậm chí còn tốt hơn và không yêu cầu so sánh bổ sung.

0

Nếu bạn muốn nói "hiệu quả nhất" theo "tốt nhất", hãy đọc tiếp.

Tôi đề xuất sử dụng phương pháp sau nếu thực sự có rất nhiều.
Chuỗi trong Chuyển đổi thực sự là một cái gì đó sẽ có trong Java 7. (Là một phần của Project Coin)

Và đây là cách ngôn ngữ Java sẽ thực hiện nó.
Đầu tiên, giá trị băm của mỗi chuỗi được tính toán. Vấn đề này sau đó là một vấn đề "switch int", có sẵn trong hầu hết ngôn ngữ hiện tại, và hiệu quả. Trong mỗi câu lệnh case, bạn kiểm tra xem đây có thực sự là chuỗi không (trong trường hợp rất hiếm, các chuỗi khác nhau có thể băm vào cùng một int).
Cá nhân tôi không thực hiện bước cuối cùng trong thực tế vì nó cần thiết phụ thuộc vào tình huống mà bạn có chương trình cụ thể, tức là các chuỗi có thể nằm dưới sự kiểm soát của lập trình viên hay không và chương trình cần phải mạnh mẽ như thế nào.

Một giả mẫu tương ứng

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

từ the fore-mentioned proposal để giúp bạn hiểu.

// 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âu hỏi là dành cho c + + (std :: string) :) – Tiago

Các vấn đề liên quan