2011-07-21 57 views
17

Tôi đang triển khai lexer tùy chỉnh trong C++ và khi cố gắng đọc trong khoảng trắng, ifstream sẽ không đọc nó. Tôi đang đọc ký tự theo ký tự bằng cách sử dụng >> và tất cả khoảng trắng đều biến mất. Có cách nào để làm cho ifstream giữ tất cả các khoảng trắng và đọc nó ra cho tôi? Tôi biết rằng khi đọc toàn bộ chuỗi, đọc sẽ dừng lại ở khoảng trắng, nhưng tôi đã hy vọng rằng bằng cách đọc ký tự theo ký tự, tôi sẽ tránh hành vi này.Đọc từ ifstream sẽ không đọc khoảng trắng

đã thử: .get(), khuyến cáo của nhiều câu trả lời, nhưng nó có tác dụng tương tự như std::noskipws, có nghĩa là, tôi nhận được tất cả các không gian bây giờ, nhưng không các kí tự xuống dòng mà tôi cần phải Lex một số cấu trúc.

Dưới đây là mã vi phạm (bình luận mở rộng cắt ngắn)

while(input >> current) { 
    always_next_struct val = always_next_struct(next); 
    if (current == L' ' || current == L'\n' || current == L'\t' || current == L'\r') { 
     continue; 
    } 
    if (current == L'/') { 
     input >> current; 
     if (current == L'/') { 
      // explicitly empty while loop 
      while(input.get(current) && current != L'\n'); 
      continue; 
     } 

Tôi đang phá vỡ trên dòng while và nhìn vào mỗi giá trị của current vì nó đến, và \r hay \n chắc chắn không nằm trong số họ- đầu vào chỉ bỏ qua dòng tiếp theo trong tệp đầu vào.

+0

Nếu bạn vi phạm dòng thời gian thì chắc chắn bạn sẽ không thấy '\ n' trong' current' như thể 'get' gặp phải' \ n' bạn đang ở trên dòng tiếp tục chứ không phải dòng trong . Hay tôi đã hiểu lầm? –

+0

'L '\ n'' là 16bit' wchar_t', không phải 8bit 'char', nhưng điều đó không có sự khác biệt. –

+0

@Charles: Sau đó, nó sẽ ngừng phá vỡ và không bắt đầu hiển thị nội dung của dòng tiếp theo trên tệp. @ Rene: Đó là một 'wifstream'. – Puppy

Trả lời

-3

Tôi đã kết thúc chỉ cần mở Windows API và sử dụng nó để đọc toàn bộ tệp vào bộ đệm trước, sau đó đọc ký tự đệm theo ký tự. Cảm ơn các bạn.

13

Có một kẻ thao túng để vô hiệu hóa hành vi bỏ qua khoảng trắng:

stream >> std::noskipws; 
+0

Tôi nhận được tất cả các không gian, nhưng vẫn không phải là dòng mới. – Puppy

+3

Và bạn cũng có thể sử dụng 'stream.unsetf (ios_base :: skipws)'; để xóa cờ định dạng đó theo cách thủ công. – sth

+0

@sth: Đó chính xác là những gì 'noskipws' làm. –

7

Nhà điều hành >> ăn khoảng trắng (space, tab, xuống dòng). Sử dụng yourstream.get() để đọc từng ký tự.

Chỉnh sửa:

Hãy coi chừng: Nền tảng (Windows, Un * x, Mac) khác với mã vạch của dòng mới. Nó có thể là '\ n', '\ r' hoặc cả hai. Nó cũng phụ thuộc vào cách bạn mở luồng tệp (văn bản hoặc nhị phân).

Chỉnh sửa (mã phân tích):

Sau

while(input.get(current) && current != L'\n'); 
    continue; 

sẽ có một \n trong current, nếu không kết thúc của tập tin là đạt. Sau đó bạn tiếp tục với vòng lặp ngoài cùng. Có ký tự đầu tiên trên dòng tiếp theo được đọc vào current. Đó không phải là những gì bạn muốn?

tôi đã cố gắng để tái tạo vấn đề của bạn (sử dụng charcin thay vì wchar_twifstream):

//: get.cpp : compile, then run: get < get.cpp 

#include <iostream> 

int main() 
{ 
    char c; 

    while (std::cin.get(c)) 
    { 
    if (c == '/') 
    { 
     char last = c; 
     if (std::cin.get(c) && c == '/') 
     { 
     // std::cout << "Read to EOL\n"; 
     while(std::cin.get(c) && c != '\n'); // this comment will be skipped 
     // std::cout << "go to next line\n"; 
     std::cin.putback(c); 
     continue; 
     } 
    else { std::cin.putback(c); c = last; } 
    } 
    std::cout << c; 
    } 
    return 0; 
} 

Chương trình này, áp dụng cho bản thân, loại bỏ tất cả bình luận dòng C++ trong sản lượng của nó. Vòng lặp bên trong không ăn hết tất cả văn bản vào cuối tệp. Xin lưu ý câu hỏi putback(c). Nếu không có dòng mới sẽ không xuất hiện.

Nếu nó không hoạt động tương tự cho wifstream, nó sẽ là rất lạ ngoại trừ một lý do: khi tập tin văn bản mở là không lưu lại dưới dạng 16bit char\n char kết thúc trong byte sai ...

+0

Không nhận '\ r', và tôi đang mở ở chế độ văn bản trên Windows, là CRLF. – Puppy

+0

@DeadMG: Khi tôi sử dụng 'int c = std :: cin.get();' Tôi nhận được ASCII 10 trên máy Windows khi tôi nhấn ENTER, vì vậy nó sẽ hoạt động với 'ifstream' theo cùng một cách. –

+0

Đó không phải là những gì sẽ xảy ra. Điều gì xảy ra là toàn bộ tập tin được đọc trong vòng lặp while và nó không thoát. Những gì được dự định là khá nhiều những gì bạn nói - khi kết thúc của dòng được tìm thấy, vòng lặp được chấm dứt và nó tiếp tục trong vòng lặp bên ngoài. – Puppy

3

Quấn luồng (hoặc bộ đệm của nó, cụ thể) trong một số std::streambuf_iterator? Điều đó sẽ bỏ qua tất cả các định dạng, và cũng cung cấp cho bạn một giao diện lặp lại tốt đẹp.

Ngoài ra, một cách tiếp cận hiệu quả hơn, và chống lừa đảo, có thể chỉ sử dụng API Win32 (hoặc Tăng) để bộ nhớ ánh xạ tệp. Sau đó, bạn có thể đi qua nó bằng cách sử dụng con trỏ đồng bằng, và bạn được đảm bảo rằng không có gì sẽ bị bỏ qua hoặc chuyển đổi bởi thời gian chạy.

+0

Ý tưởng thú vị. Tôi đã không thực sự sử dụng mà lớp iterator cụ thể trước, tôi sẽ xem – Puppy

+0

Tôi đã tìm thấy rằng iterator này là khá nhiều cách duy nhất để làm việc với IOStreams, nếu bạn muốn bất kỳ loại kiểm soát đối với những gì bạn đang đang làm và những gì đang xảy ra. Nó vẫn còn chậm, tất nhiên, như bạn mong đợi bất cứ điều gì kết hợp IOStreams (chậm) với mỗi ký tự I/O (cũng chậm) được. Nhưng nó đã có tác dụng! – jalf

2

Trình trích xuất luồng hoạt động giống nhau và bỏ qua khoảng trắng.

Nếu bạn muốn đọc từng byte, bạn có thể sử dụng các chức năng nhập chưa định dạng, như stream.get(c).

+0

Như câu trả lời của @ CharlesBailey: Tôi vẫn không nhận được ký tự mới. – Puppy

2

Tại sao không chỉ sử dụng getline?

Bạn sẽ nhận được tất cả các khoảng trắng, và trong khi bạn sẽ không nhận cuối dòng nhân vật, bạn vẫn sẽ biết được nơi họ nằm :)

2

Bạn có thể mở dòng trong chế độ nhị phân:

std::wifstream stream(filename, std::ios::binary); 

Bạn sẽ mất mọi hoạt động định dạng được cung cấp luồng nếu bạn làm điều này.

Các tùy chọn khác là để đọc toàn bộ dòng vào một chuỗi và sau đó xử lý chuỗi:

std::wostringstream ss; 
ss << filestream.rdbuf(); 

tất nhiên, nhận được chuỗi từ ostringstream rquires một bản sao bổ sung của chuỗi, vì vậy bạn có thể xem xét thay đổi điều này tại một số thời điểm để sử dụng luồng tùy chỉnh nếu bạn cảm thấy thích mạo hiểm. EDIT: người khác đề cập đến istreambuf_iterator, có lẽ là một cách tốt hơn để làm điều đó hơn là đọc toàn bộ luồng vào chuỗi.

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