2010-11-16 33 views
5

Đối với chương trình này, tôi chỉ sử dụng các dấu tách trường từ các tệp dữ liệu trong tập lệnh shell. Nhưng tôi đang cố gắng sử dụng hàm thư viện chuẩn ifstream() để đọc từ một tệp dữ liệu. Vấn đề duy nhất là tôi đang nhận được dữ liệu như vậyC++ chức năng ifstream và phân tách trường

A: KT5: 14: bàn làm việc:

này là dành cho một bảng băm, và tôi cần phải tách biệt các giá trị trong dòng cho cấu trúc dữ liệu như cũng như loại giao dịch. Tôi đã tìm kiếm trên web và không tìm thấy nhiều trên phân cách trường và những gì tôi đã tìm thấy khá khó hiểu.

Câu hỏi sau đó là có cách nào để đặt trình tách trường với hàm ifstream hoặc có một hàm i/o thư viện chuẩn khác mà tôi nên sử dụng không?

Cảm ơn.

Trả lời

4

getline cung cấp cho bạn tùy chọn chỉ định dấu phân cách. Sau đó bạn có thể đọc các thông tin từ một dòng suối như một chuỗi các string ngăn cách bởi _Delim:

template<class CharType, class Traits, class Allocator> 
    basic_istream< CharType, Traits >& getline(
     basic_istream< CharType, Traits >& _Istr, 
     basic_string< CharType, Traits, Allocator >& _Str, 
     CharType _Delim 
    ); 

Nếu đây là cấu trúc thống nhất dữ liệu mà nó có thể có ích để xác định một struct để chứa nó và thực hiện operator>> để tải mỗi trường hợp từ luồng, sử dụng hàm trên bên trong mã nhà điều hành.

Nếu bạn phải xử lý nhiều dòng (để dòng mới là dấu tách bản ghi và: dấu tách trường), hãy tải từng dòng lần lượt thành stringstream sử dụng basic_istream::getline và sau đó xử lý dòng vào trường như minh họa.

+1

Chà ... và không phải là một cách tốt. Tôi nghĩ rằng tôi sẽ dính vào C. – onemasse

+0

cảm ơn Steve !!! – rajh2504

+0

@onemasse, erm: tuyên bố thực sự trông giống như: "istream & getline (istream & is, string & str, char delim);', không quá tệ bây giờ là nó? :), không phải đề cập đến những gì 'std :: getline' cung cấp cho bạn hơn C tương đương! :) – Nim

5

@Steve Townsend đã chỉ ra một khả năng. Nếu bạn thích sử dụng operator>> thay vì std::getline, bạn cũng có thể làm điều đó. An istream luôn xử lý khoảng trống làm dấu phân cách. Mỗi luồng có một ngôn ngữ được liên kết và mỗi miền địa phương bao gồm một khía cạnh ctype. Điều đó ctype khía cạnh là những gì các istream sử dụng để xác định những ký tự đầu vào là khoảng trắng. Trong trường hợp của bạn, có vẻ như bạn muốn luồng chỉ xử lý các dòng mới và dấu hai chấm là "khoảng trắng", nghĩa là ký tự khoảng trắng được coi là ký tự "bình thường" chứ không phải dấu phân cách.

Để làm điều đó, bạn có thể tạo ra một khía cạnh CType như thế này:

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()); 

     rc['\n'] = std::ctype_base::space; 
     rc[':'] = std::ctype_base::space; 
     return &rc[0]; 
    } 
}; 

Để sử dụng, điều này, bạn phải "thấm nhuần" dòng với ngôn ngữ sử dụng khía cạnh này:

int main() { 
    std::stringstream input("A:KT5:14:executive desk:"); 

    // have the stream use our ctype facet: 
    input.imbue(std::locale(std::locale(), new field_reader())); 

    // copy fields from the stream to standard output, one per line: 
    std::copy(std::istream_iterator<std::string>(input), 
       std::istream_iterator<std::string>(), 
       std::ostream_iterator<std::string>(std::cout, "\n")); 
    return 0; 
} 

Tôi là người đầu tiên thừa nhận, tuy nhiên, điều này có một số thiếu sót. Trước hết, ngôn ngữ và khía cạnh thường khá kém tài liệu, do đó, nhất Trình lập trình C++ có khả năng tìm thấy điều này khá khó hiểu (đặc biệt là khi tất cả các công việc thực sự xảy ra "dưới bìa", để nói).

Một khả năng khác là sử dụng Boost Tokenizer. Nói chung, đây là một chút hơn hoạt động để sử dụng - nó sẽ yêu cầu bạn làm điều gì đó như đọc chuỗi, sau đó chia nhỏ riêng biệt.Đồng thời, nó được viết thành văn bản, khá phổ biến và phù hợp hơn với các định kiến ​​của mọi người về cách làm những việc như thế, rằng có rất ít người có thể dễ dàng theo dõi hơn bất chấp sự phức tạp thêm.

+1

Tôi đồng ý rằng Locales/facets được hiểu rất ít bởi rất nhiều nhà phát triển C++. Nhưng đó là bởi vì rất ít người thực sự quan tâm đến I18N hoặc L10N mã của họ và do đó không bao giờ bận tâm học tập công cụ này. Nhưng đó là một lý do khác để tiếp tục đưa nó lên càng thường xuyên càng tốt để cho thấy rằng khi được sử dụng đúng cách nó làm cho mã chính dễ dàng hơn nhiều để viết và hiểu. Đó là một mẹo khác mà tôi đã học được với các khía cạnh và có ý định sử dụng nó càng sớm càng tốt. –