2011-10-01 39 views
27

Tôi có một số văn bản (văn bản có ý nghĩa hoặc biểu thức số học) và tôi muốn chia thành các từ.
Nếu tôi đã có một dấu phân cách duy nhất, tôi muốn sử dụng:Tách một chuỗi thành các từ theo nhiều dấu phân cách

std::stringstream stringStream(inputString); 
std::string word; 
while(std::getline(stringStream, word, delimiter)) 
{ 
    wordVector.push_back(word); 
} 

Làm thế nào tôi có thể phá vỡ chuỗi thành tokens với nhiều delimiters?

+0

Boost.StringAlgorithm hoặc Boost.Tokenizer sẽ hữu ích. –

+0

Hoặc, một số ý tưởng bạn có thể nhận được từ câu trả lời này: http://stackoverflow.com/questions/4888879/elegant-ways-to-count-the-frequency-of-words-in-a-file – Nawaz

+3

@ K-ballo : Theo câu hỏi, bạn không nên sử dụng các thư viện bên ngoài như Boost. – deepmax

Trả lời

36

Giả sử một trong các dấu phân cách là dòng mới, sau đây đọc dòng và chia tách nó thêm bằng dấu phân tách. Đối với ví dụ này tôi đã chọn không gian phân cách, dấu nháy đơn và dấu chấm phẩy.

std::stringstream stringStream(inputString); 
std::string line; 
while(std::getline(stringStream, line)) 
{ 
    std::size_t prev = 0, pos; 
    while ((pos = line.find_first_of(" ';", prev)) != std::string::npos) 
    { 
     if (pos > prev) 
      wordVector.push_back(line.substr(prev, pos-prev)); 
     prev = pos+1; 
    } 
    if (prev < line.length()) 
     wordVector.push_back(line.substr(prev, std::string::npos)); 
} 
+3

Bạn đang quá nhanh đối với tôi: p Nếu dòng mới không phải là dấu tách, thì chỉ cần chọn một trong các dấu phân cách "thông thường" (và xóa nó khỏi vòng lặp bên trong) sẽ hoạt động. –

16

Nếu bạn có tăng, bạn có thể sử dụng:

#include <boost/algorithm/string.hpp> 
std::string inputString("One!Two,Three:Four"); 
std::string delimiters("|,:"); 
std::vector<std::string> parts; 
boost::split(parts, inputString, boost::is_any_of(delimiters)); 
0

Nếu bạn thú vị trong làm thế nào để làm điều đó cho mình và không sử dụng tăng.

Giả sử chuỗi dấu phân cách có thể rất dài - hãy nói M, kiểm tra mỗi char trong chuỗi của bạn nếu nó là dấu phân cách, sẽ có giá O (M) mỗi, vì vậy làm như vậy trong vòng lặp cho tất cả ký tự trong thư gốc của bạn chuỗi, hãy nói theo chiều dài N, là O (M * N).

Tôi sẽ sử dụng từ điển (như bản đồ - "dấu tách" đến "booleans" - nhưng ở đây tôi sẽ sử dụng mảng boolean đơn giản có giá trị index = ascii cho mỗi dấu phân tách).

Bây giờ lặp lại trên chuỗi và kiểm tra xem char là dấu phân cách là O (1), cuối cùng cho chúng ta O (N) tổng thể.

Đây là mẫu mã của tôi:

const int dictSize = 256;  

vector<string> tokenizeMyString(const string &s, const string &del) 
{ 
    static bool dict[dictSize] = { false}; 

    vector<string> res; 
    for (int i = 0; i < del.size(); ++i) {  
     dict[del[i]] = true; 
    } 

    string token(""); 
    for (auto &i : s) { 
     if (dict[i]) { 
      if (!token.empty()) { 
       res.push_back(token); 
       token.clear(); 
      }   
     } 
     else { 
      token += i; 
     } 
    } 
    if (!token.empty()) { 
     res.push_back(token); 
    } 
    return res; 
} 


int main() 
{ 
    string delString = "MyDog:Odie, MyCat:Garfield MyNumber:1001001"; 
//the delimiters are " " (space) and "," (comma) 
    vector<string> res = tokenizeMyString(delString, " ,"); 

    for (auto &i : res) { 

     cout << "token: " << i << endl; 
    } 
return 0; 
} 

Lưu ý: tokenizeMyString trả về vector theo giá trị và tạo ra nó trên stack đầu tiên, vì vậy chúng tôi đang sử dụng ở đây sức mạnh của trình biên dịch >>> RVO - giá trị trả về tối ưu hóa :)

2

tôi không biết tại sao không ai chỉ ra cách sử dụng, nhưng ở đây nó là:

const std::string delims(";,:. \n\t"); 
inline bool isDelim(char c) { 
    for (int i = 0; i < delims.size(); ++i) 
     if (delims[i] == c) 
      return true; 
    return false; 
} 

và chức năng:

std::stringstream stringStream(inputString); 
std::string word; char c; 

while (stringStream) { 
    word.clear(); 

    // Read word 
    while (!isDelim((c = stringStream.get()))) 
     word.push_back(c); 
    if (c != EOF) 
     stringStream.unget(); 

    wordVector.push_back(word); 

    // Read delims 
    while (isDelim((c = stringStream.get()))); 
    if (c != EOF) 
     stringStream.unget(); 
} 

Bằng cách này bạn có thể làm điều gì đó hữu ích với các món ăn ngon nếu bạn muốn.

+0

Bạn có thể di chuyển std :: string word; và char c; bên trong vòng lặp và tránh sử dụng rõ ràng() ...các biến phải là địa phương và thời gian sống ngắn nhất có thể. – Mohan

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