簡體   English   中英

從 ifstream 讀取不會讀取空格

[英]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 這不是你想要的嗎?

我試圖重現您的問題(使用charcin而不是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;
}

該程序應用於自身,消除了其 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM