[英]Reading from ifstream won't read whitespace
我在 C++ 中實現了一個自定義詞法分析器,當嘗試讀取空白時,ifstream 不會將其讀出。 我正在使用>>
逐個字符地閱讀,所有的空格都消失了。 有什么方法可以讓 ifstream 保留所有的空白並把它讀給我聽? 我知道在讀取整個字符串時,讀取將在空格處停止,但我希望通過逐個字符讀取,我會避免這種行為。
嘗試過: .get()
,許多答案都推薦,但它與std::noskipws
具有相同的效果,也就是說,我現在得到了所有空格,但不是我需要對某些結構進行 lex 的換行符。
這是有問題的代碼(擴展注釋被截斷)
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;
}
我在while
行中斷並查看current
的每個值,並且\r
或\n
絕對不在其中 - 輸入只是跳到輸入文件中的下一行。
有一個操縱器可以禁用空格跳過行為:
stream >> std::noskipws;
運算符>> 吃掉空格(空格、制表符、換行符)。 使用yourstream.get()
讀取每個字符。
編輯:
注意:平台(Windows、Un*x、Mac)的換行編碼不同。 它可以是“\n”、“\r”或兩者兼而有之。 它還取決於您如何打開文件 stream(文本或二進制)。
編輯(分析代碼):
后
while(input.get(current) && current != L'\n');
continue;
如果未到達文件末尾,則current
中將有一個\n
。 之后,您繼續最外面的 while 循環。 在那里,下一行的第一個字符被讀入current
。 這不是你想要的嗎?
我試圖重現您的問題(使用char
和cin
而不是wchar_t
和wifstream
):
//: 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;
}
該程序應用於自身,消除了其 output 中的所有 C++ 行注釋。 內部 while 循環不會吃掉所有文本到文件末尾。 請注意putback(c)
語句。 沒有它,換行符就不會出現。
如果它對wifstream
,那將是非常奇怪的,除了一個原因:當打開的文本文件沒有保存為 16 位字符並且\n
字符以錯誤的字節結束時......
您可以在二進制模式下打開 stream:
std::wifstream stream(filename, std::ios::binary);
如果您這樣做,您將丟失任何格式化操作,只要我提供 stream。
另一種選擇是將整個 stream 讀入一個字符串,然后處理該字符串:
std::wostringstream ss;
ss << filestream.rdbuf();
當然,從 ostringstream 獲取字符串需要額外的字符串副本,因此如果您喜歡冒險,您可以考慮在某個時候更改它以使用自定義 stream。 編輯:其他人提到 istreambuf_iterator,這可能是比將整個 stream 讀入字符串更好的方法。
將 stream (或其緩沖區,特別是)包裝在std::streambuf_iterator
中? 這應該忽略所有格式,並為您提供一個不錯的迭代器接口。
或者,一種更有效、更簡單的方法可能只是使用 Win32 API(或 Boost)來對文件進行內存映射。 然后,您可以使用普通指針遍歷它,並保證運行時不會跳過或轉換任何內容。
您可以將 stream 包裝在std::streambuf_iterator中,以獲取帶有所有空格和換行符的數據。
/*Open the stream in default mode.*/
std::ifstream myfile("myfile.txt");
if(myfile.good()) {
/*Read data using streambuffer iterators.*/
vector<char> buf((std::istreambuf_iterator<char>(myfile)), (std::istreambuf_iterator<char>()));
/*str_buf holds all the data including whitespaces and newline .*/
string str_buf(buf.begin(),buf.end());
myfile.close();
}
默認情況下,這個skipws 標志已經在 ifstream object 上設置,所以我們必須禁用它。 ifstream object 具有這些默認標志,因為 std::basic_ios::init 在每個新的 ios_base object 上調用( 更多詳細信息)。 以下任何一項都可以:
in_stream.unsetf(std::ios_base::skipws);
in_stream >> std::noskipws; // Using the extraction operator, same as below
std::noskipws(in_stream); // Explicitly calling noskipws instead of using operator>>
其他標志列在cpp reference上。
stream 提取器的行為相同並跳過空格。
如果要讀取每個字節,可以使用未格式化的輸入函數,例如stream.get(c)
。
為什么不簡單地使用getline
?
你會得到所有的空格,雖然你不會得到行尾字符,但你仍然會知道它們在哪里:)
只需使用 getline。
while (getline(input,current))
{
cout<<current<<"\n";
}
我最終只是打開 Windows API 並使用它首先將整個文件讀入緩沖區,然后逐個字符地讀取該緩沖區。 多謝你們。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.