2012-04-07 69 views
20

Tôi biết đây là vấn đề khá dễ nhưng tôi chỉ muốn giải quyết nó một lần và cho tất cảTách chuỗi bằng ký tự

Tôi chỉ muốn chia chuỗi thành mảng bằng ký tự làm tách dấu phân cách. (Giống như chức năng nổi tiếng của C# .Split().Tôi có thể áp dụng cách tiếp cận bạo lực nhưng tôi tự hỏi liệu có điều gì tốt hơn không.

Cho đến nay tôi đã tìm kiếm và có thể là gần nhất cách tiếp cận giải pháp là việc sử dụng strtok(), tuy nhiên do nó bất tiện (chuyển đổi chuỗi của bạn đến một mảng char vv) tôi không thích sử dụng nó. có cách nào dễ dàng hơn để thực hiện điều này?

Lưu ý: Tôi muốn nhấn mạnh điều này bởi vì mọi người có thể hỏi "Làm thế nào đến bạo lực không hoạt động". Giải pháp brute-force của tôi là tạo vòng lặp và sử dụng substr() chức năng bên trong. Tuy nhiên vì nó yêu cầu điểm bắt đầu và độ dài, nó không thành công khi tôi muốn chia nhỏ một ngày. Bởi vì người dùng có thể nhập nó như là 7/12/2012 hoặc 07/3/2011, nơi tôi thực sự có thể cho biết độ dài trước khi tính toán vị trí tiếp theo của dấu phân cách '/'.

+0

bản sao có thể có của [Tách chuỗi C++] (http://stackoverflow.com/questions/275404/splitting-string-c) –

Trả lời

49

Sử dụng vectơ, chuỗi và chuỗi. Một chút cồng kềnh nhưng nó làm các trick.

std::stringstream test("this_is_a_test_string"); 
std::string segment; 
std::vector<std::string> seglist; 

while(std::getline(test, segment, '_')) 
{ 
    seglist.push_back(segment); 
} 
+0

Trên thực tế loại tiếp cận này chính xác những gì tôi đang tìm kiếm. Khá dễ hiểu, không sử dụng thư viện bên ngoài, chỉ rất thẳng về phía trước. Cảm ơn @thelazydeveloper! – Ali

+0

Vẫn là giải pháp tốt nhất hiện có! –

2

Hãy xem boost::tokenizer

Nếu bạn muốn cuộn lên phương pháp riêng của bạn, bạn có thể sử dụng std::string::find() để xác định các điểm chia tách.

+2

Cảm ơn bạn đã tìm mẹo tìm chuỗi. Luôn yêu thích giải pháp ** std **! – Ali

9

Boost có split() bạn đang tìm kiếm trong algorithm/string.hpp:

std::string sample = "07/3/2011"; 
std::vector<string> strs; 
boost::split(strs, sample, boost::is_any_of("/")); 
10

Một cách khác (C++ 11/tăng) đối với những người thích RegEx. Cá nhân tôi là một fan hâm mộ lớn của RegEx cho loại dữ liệu này. IMO mạnh hơn rất nhiều so với việc tách chuỗi bằng cách sử dụng dấu phân cách vì bạn có thể chọn thông minh hơn về những gì cấu thành dữ liệu "hợp lệ" nếu bạn muốn.

#include <string> 
#include <algorithm> // copy 
#include <iterator>  // back_inserter 
#include <regex>  // regex, sregex_token_iterator 
#include <vector> 

int main() 
{ 
    std::string str = "08/04/2012"; 
    std::vector<std::string> tokens; 
    std::regex re("\\d+"); 

    //start/end points of tokens in str 
    std::sregex_token_iterator 
     begin(str.begin(), str.end(), re), 
     end; 

    std::copy(begin, end, std::back_inserter(tokens)); 
} 
4

Một khả năng khác là truyền luồng có miền địa phương sử dụng khía cạnh đặc biệt ctype. Một luồng sử dụng khía cạnh ctype để xác định "khoảng trắng" là gì, mà nó xử lý như dấu phân cách. Với một khía cạnh ctype phân loại ký tự phân cách của bạn là khoảng trắng, việc đọc có thể khá tầm thường.Dưới đây là một cách để thực hiện các khía cạnh:

struct field_reader: std::ctype<char> { 

    field_reader(): std::ctype<char>(get_table()) {} 

    static std::ctype_base::mask const* get_table() { 
     static std::vector<std::ctype_base::mask> 
      rc(table_size, std::ctype_base::mask()); 

     // we'll assume dates are either a/b/c or a-b-c: 
     rc['/'] = std::ctype_base::space; 
     rc['-'] = std::ctype_base::space; 
     return &rc[0]; 
    } 
}; 

Chúng tôi sử dụng bằng cách sử dụng imbue để kể một dòng để sử dụng một miền địa phương bao gồm nó, sau đó đọc dữ liệu từ dòng rằng:

std::istringstream in("07/3/2011"); 
in.imbue(std::locale(std::locale(), new field_reader); 

Với điều đó tại chỗ, tách trở nên gần như không đáng kể - chỉ cần khởi tạo một vector sử dụng một vài istream_iterator s để đọc các mảnh ghép khỏi chuỗi (được nhúng trong istringstream):

std::vector<std::string>((std::istream_iterator<std::string>(in), 
          std::istream_iterator<std::string>()); 

Rõ ràng điều này có xu hướng hướng tới mức quá mức nếu bạn chỉ sử dụng nó ở một nơi. Nếu bạn sử dụng nó nhiều, tuy nhiên, nó có thể đi một chặng đường dài để giữ phần còn lại của mã khá sạch sẽ.

0

Tôi vốn không thích stringstream, mặc dù tôi không chắc chắn lý do. Hôm nay, tôi đã viết chức năng này để cho phép tách một std::string bởi bất kỳ ký tự hoặc chuỗi tùy ý nào thành một vectơ. Tôi biết câu hỏi này là cũ, nhưng tôi muốn chia sẻ một cách khác để tách std::string.

Mã này bỏ qua một phần của chuỗi mà bạn tách ra từ kết quả hoàn toàn, mặc dù nó có thể dễ dàng sửa đổi để bao gồm chúng.

#include <string> 
#include <vector> 

void split(std::string str, std::string splitBy, std::vector<std::string>& tokens) 
{ 
    /* Store the original string in the array, so we can loop the rest 
    * of the algorithm. */ 
    tokens.push_back(str); 

    // Store the split index in a 'size_t' (unsigned integer) type. 
    size_t splitAt; 
    // Store the size of what we're splicing out. 
    size_t splitLen = splitBy.size(); 
    // Create a string for temporarily storing the fragment we're processing. 
    std::string frag; 
    // Loop infinitely - break is internal. 
    while(true) 
    { 
     /* Store the last string in the vector, which is the only logical 
     * candidate for processing. */ 
     frag = tokens.back(); 
     /* The index where the split is. */ 
     splitAt = frag.find(splitBy); 
     // If we didn't find a new split point... 
     if(splitAt == string::npos) 
     { 
      // Break the loop and (implicitly) return. 
      break; 
     } 
     /* Put everything from the left side of the split where the string 
     * being processed used to be. */ 
     tokens.back() = frag.substr(0, splitAt); 
     /* Push everything from the right side of the split to the next empty 
     * index in the vector. */ 
     tokens.push_back(frag.substr(splitAt+splitLen, frag.size()-(splitAt+splitLen))); 
    } 
} 

Để sử dụng, chỉ cần gọi như vậy ...

std::string foo = "This is some string I want to split by spaces."; 
std::vector<std::string> results; 
split(foo, " ", results); 

Bây giờ bạn có thể truy cập tất cả các kết quả trong các vector theo ý thích. Đơn giản như vậy - không có stringstream, không có thư viện của bên thứ ba, không quay trở lại C!

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