2009-05-20 48 views
8

Tôi mới tham gia lập trình. Tôi đã cố gắng để viết một hàm trong C++ mà phát nổ nội dung của một chuỗi thành một mảng chuỗi tại một tham số nhất định, ví dụ:Làm thế nào tôi có thể chia chuỗi bằng dấu phân tách thành một mảng?

string str = "___this_ is__ th_e str__ing we__ will use__"; 

nên trả lại chuỗi mảng:

cout << stringArray[0]; // 'this' 
cout << stringArray[1]; // ' is' 
cout << stringArray[2]; // ' th' 
cout << stringArray[3]; // 'e str' 
cout << stringArray[4]; // 'ing we' 
cout << stringArray[5]; // ' will use' 

tôi có thể tokenize chuỗi chỉ tốt, nhưng phần khó nhất đối với tôi là làm thế nào tôi có thể xác định số lượng các phần tử trong stringArray trước khi gán nó cho chuỗi hiện tại và cũng như cách trả về stringArray từ hàm.

Ai đó có thể chỉ cho tôi cách viết hàm này không?

Chỉnh sửa1: Tôi không nhất thiết cần kết quả nằm trong mảng chuỗi chỉ bất kỳ vùng chứa nào mà tôi có thể gọi dưới dạng biến thông thường với một số loại lập chỉ mục.

+0

Bài tập về nhà, không chừng? Đó là OK, tất nhiên, nhưng tôi từ câu trả lời bài tập về nhà một cách khác nhau ... – dmckee

+0

trùng lặp: http://stackoverflow.com/questions/53849/how-do-i-tokenize-a-string-in-c – lothar

+0

@Iothar câu trả lời ở đây có vẻ hiệu quả hơn. – Arnthor

Trả lời

10

Đây là nỗ lực đầu tiên của tôi tại đây sử dụng các vector và chuỗi:

vector<string> explode(const string& str, const char& ch) { 
    string next; 
    vector<string> result; 

    // For each character in the string 
    for (string::const_iterator it = str.begin(); it != str.end(); it++) { 
     // If we've hit the terminal character 
     if (*it == ch) { 
      // If we have some characters accumulated 
      if (!next.empty()) { 
       // Add them to the result vector 
       result.push_back(next); 
       next.clear(); 
      } 
     } else { 
      // Accumulate the next character into the sequence 
      next += *it; 
     } 
    } 
    if (!next.empty()) 
     result.push_back(next); 
    return result; 
} 

Hy vọng rằng điều này sẽ cho bạn một số loại ý tưởng về làm thế nào để đi về việc này.Mở chuỗi ví dụ của bạn nó sẽ trả về kết quả đúng với mã này thử nghiệm:

int main (int, char const **) { 
    std::string blah = "___this_ is__ th_e str__ing we__ will use__"; 
    std::vector<std::string> result = explode(blah, '_'); 

    for (size_t i = 0; i < result.size(); i++) { 
     cout << "\"" << result[i] << "\"" << endl; 
    } 
    return 0; 
} 
+1

Tham số đầu tiên để phát nổ() phải là một tham chiếu không đổi. Trình biên dịch sau đó sẽ khiếu nại, vì vậy 'nó' cần phải là một chuỗi :: const_iterator. – ralphtheninja

+0

@Magnus: Cảm ơn, đã thêm sửa lỗi đó :) –

+1

Bạn nên kiểm tra xem 'next' có trống không và nếu vậy hãy nối nó vào kết quả SAU KHI LOOP. Nếu không, phần tử cuối cùng sau khi phát nổ char sẽ không được chứa. – ddinchev

1

Nếu bạn nhấn mạnh vào làm stringArray một mảng như oppossed đến một std::vector<> (đó sẽ là điều đúng đắn nên làm), bạn phải hoặc là:

  1. Làm cho hai đèo (một để đếm, bạn sẽ thấy)
  2. Tự mình triển khai mảng động.

Sử dụng vector dễ dàng hơn vector::push_back() nối thêm công cụ mới vào cuối. Vì vậy:

vector* explode(string s){ 
    vector<string> *v = new vector<string> 
    //... 
    // in a loop 
    v->push_back(string_fragment); 
    //... 
    return v; 
} 

Không cần thiết sau khi tất cả trái trong cho đầy đủ.

Để trả về mảng chuỗi bạn sử dụng char **.

Như trong

char ** explode(const char *in){ 
    ... 

} 

BTW-- Làm thế nào chức năng gọi điện thoại sẽ biết có bao nhiêu yếu tố trong mảng trở lại? Bạn sẽ phải giải quyết điều đó. Sử dụng std::vector<> trừ khi bạn bị giới hạn bởi các lực lượng bên ngoài ...

+0

v-> push_back (string_fragment); – ralphtheninja

+0

@Magnus: Rất tiếc. Cảm ơn. – dmckee

+0

Tôi nghĩ rằng đi qua một vector phân bổ stack trở lại, hoặc tham gia vào một vector để điền vào sẽ là một lựa chọn tốt hơn sau đó phân bổ một vector nguyên trong chức năng, sau đó đi qua trách nhiệm xóa cho khách hàng. – GManNickG

1

Bạn có thể sử dụng vectơ của chuỗi (std::vector<std::string>), thêm mỗi mã thông báo vào nó với push_back và sau đó trả lại mã từ chức năng mã thông báo của bạn.

1

Sử dụng tiêu chuẩn :: vector dưới dạng mảng động và trả về kết quả của bạn.

1

Có lẽ bạn nên sử dụng danh sách thay vì mảng. Bằng cách đó bạn sẽ không cần phải biết số lượng các yếu tố trước thời hạn. Bạn cũng có thể xem xét sử dụng các container STL.

8

Sử dụng STL (xin lỗi không có trình biên dịch không được kiểm tra)

#include <vector> 
#include <string> 
#include <sstream> 

int main() 
{ 
    std::vector<std::string> result; 

    std::string str = "___this_ is__ th_e str__ing we__ will use__"; 

    std::stringstream data(str); 

    std::string line; 
    while(std::getline(data,line,'_')) 
    { 
     result.push_back(line); // Note: You may get a couple of blank lines 
           // When multiple underscores are beside each other. 
    } 
} 

// hoặc xác định một mã thông báo

#include <vector> 
#include <string> 
#include <iterator> 
#include <algorithm> 
#include <sstream> 

struct Token: public std::string // Yes I know this is nasty. 
{         // But it is just to demosntrate the principle.  
}; 

std::istream& operator>>(std::istream& s,Token& t) 
{ 
    std::getline(s,t,'_'); 

    // *** 
    // Remove extra '_' characters from the stream. 
    char c; 
    while(s && ((c = s.get()) != '_')) {/*Do Nothing*/} 
    if (s) 
    { 
     s.unget(); // Put back the last char as it is not '_' 
    } 
    return s; 
} 

int main() 
{ 
    std::vector<std::string> result; 

    std::string str = "___this_ is__ th_e str__ing we__ will use__"; 

    std::stringstream data(str); 

    std::copy(std::istream_iterator<Token>(data), 
       std::istream_iterator<Token>() 
       std::back_inserter(result) 
      ); 
} 
+0

Vì vậy, hãy thêm dấu kiểm trong vòng lặp while để bỏ qua "dòng" trống. – jmucchiello

+1

Đó là một bài tập cho người dùng. –

0

Chờ cho đến khi lớp cấu trúc dữ liệu của bạn và sau đó mã nó với một danh sách liên kết. Nếu nó là cho bài tập về nhà mặc dù, bạn có thể có được để đi với chỉ cần initing mảng là rất lớn.

0

Đoạn code dưới đây:

template <typename OutputIterator> 
int explode(const string &s, const char c, OutputIterator output) { 
    stringstream data(s); 
    string line; 
    int i=0; 
    while(std::getline(data,line,c)) { *output++ = line; i++; } 
    return i; 
} 

int main(...) { 
    string test="H:AMBV4:2:182.45:182.45:182.45:182.45:182.41:32:17700:3229365:201008121711:0"; 
    cout << test << endl; 
    vector<string> event; 
**This is the main call** 
    int evts = explode(test,':', back_inserter(event)); 
    for (int k=0; k<evts; k++) 
    cout << event[k] << "~"; 
    cout << endl; 
} 

Đầu ra

H:AMBV4:2:182.45:182.45:182.45:182.45:182.41:32:17700:3229365:201008121711:0 
H~AMBV4~2~182.45~182.45~182.45~182.45~182.41~32~17700~3229365~201008121711~0~ 
2

Nó làm việc cho tôi:

#include <iostream> 
#include <vector> 
#include <string> 

using namespace std; 

vector<string> explode(const string &delimiter, const string &explodeme); 

int main(int argc, char *argv[]) 
{ 
    string str = "I have a lovely bunch of cocoa nuts"; 
    cout<<str<<endl; 
    vector<string> v = explode(" ", str); 
    for(int i=0; i<v.size(); i++) 
     cout <<i << " ["<< v[i] <<"] " <<endl; 
} 

vector<string> explode(const string &delimiter, const string &str) 
{ 
    vector<string> arr; 

    int strleng = str.length(); 
    int delleng = delimiter.length(); 
    if (delleng==0) 
     return arr;//no change 

    int i=0; 
    int k=0; 
    while(i<strleng) 
    { 
     int j=0; 
     while (i+j<strleng && j<delleng && str[i+j]==delimiter[j]) 
      j++; 
     if (j==delleng)//found delimiter 
     { 
      arr.push_back( str.substr(k, i-k)); 
      i+=delleng; 
      k=i; 
     } 
     else 
     { 
      i++; 
     } 
    } 
    arr.push_back( str.substr(k, i-k)); 
    return arr; 
} 

nguồn:http://www.zedwood.com/article/106/cpp-explode-function

0

Đây là mã được nấu chín của tôi (đã hoàn thành). Có thể nó hữu ích cho một số người có cùng nhu cầu.

#include <string> 
#include <iostream> 
#include <sstream> 
#include <vector> 
using namespace std; 

int main(){ 
     std::string s = "scott:tiger:mushroom"; 
     std::string delimiter = ":"; 

     std::vector<std::string> outputArr; 
     size_t pos = 0; 
     std::string token; 
     while ((pos = s.find(delimiter)) != std::string::npos) { 
      token = s.substr(0, pos); 
      s.erase(0, pos + delimiter.length()); 
      outputArr.push_back(token); 
     } 
     outputArr.push_back(s); 

     // Printing Array to see the results 
     std::cout<<"====================================================================================\n"; 
     for (int i=0;i<outputArr.size();i++){ 
       std::cout<<outputArr[i]<<"\n"; 
     } 
     std::cout<<"====================================================================================\n"; 
} 

Chúc mừng !!

0

Tôi nghĩ rằng tôi đã viết một giải pháp đơn giản hơn nhiều.

std::vector<std::string> explode(const std::string& string, const char delimiter) { 

std::vector<std::string> result; 
unsigned int start = 0, pos = 0; 

while (pos != string.length()) { 
    if (string.at(pos) == delimiter || pos + 1 == string.length()) { 
     unsigned int size = (pos - start) + ((pos + 1) == string.length() ? 1 : 0); 
     if (size != 0) { // Make this 'if' as a option? like a parameter with removeEmptyString? 
      result.push_back(string.substr(start, size)); 
     } 
     start = pos + 1; 
    } 
    pos++; 
} 

return std::move(result); 

}

0

này đã làm việc cho tôi:

#include <iostream> 
#include <vector> 
#include <string> 
#include <sstream> 

using namespace std; 

vector<string> split(string str, char delimiter) { 
    vector<string> internal; 
    stringstream ss(str); // Turn the string into a stream. 
    string tok; 

    while(getline(ss, tok, delimiter)) { 
    internal.push_back(tok); 
    } 

    return internal; 
} 

int main(int argc, char **argv) { 
    string myCSV = "one,two,three,four"; 
    vector<string> sep = split(myCSV, ','); 

    // If using C++11 (which I recommend) 
    /* for(string t : sep) 
    * cout << t << endl; 
    */ 

    for(int i = 0; i < sep.size(); ++i) 
    cout << sep[i] << endl; 
} 

Nguồn: http://code.runnable.com/VHb0hWMZp-ws1gAr/splitting-a-string-into-a-vector-for-c%2B%2B

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