Подтвердить что ты не робот

Чтение из ifstream не будет читать пробелы

Я реализую пользовательский лексер на С++, и когда вы пытаетесь прочитать в пробеле, ifstream не будет его читать. Я читаю символ по символу, используя >>, и все пробелы исчезли. Есть ли способ сделать ifstream держать все пробелы и прочитать его мне? Я знаю, что при чтении целых строк чтение будет останавливаться в пробеле, но я надеялся, что, читая характер по характеру, я бы избегал этого поведения.

Попытка: .get(), рекомендованная многими ответами, но имеет тот же эффект, что и std::noskipws, т.е. теперь я получаю все пробелы, но не символ новой строки, который мне нужен для каких-то конструкций.

Здесь код нарушения (расширенные комментарии укорочены)

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 определенно не среди них: вход просто переходит к следующей строке в входной файл.

4b9b3361

Ответ 1

В итоге я просто взломал Windows API и использовал его, чтобы сначала прочитать весь файл в буфер, а затем прочитать этот символ буфера по символу. Спасибо, ребята.

Ответ 2

Существует манипулятор, позволяющий отключить поведение пропущенных пробелов:

stream >> std::noskipws;

Ответ 3

Оператор → ест пробел (пробел, табуляция, новая строка). Используйте yourstream.get() для чтения каждого символа.

Edit:

Остерегайтесь: платформы (Windows, Un * x, Mac) отличаются кодировкой новой строки. Это могут быть "\n", "\ r" или оба. Это также зависит от того, как вы открываете поток файлов (текстовый или двоичный).

Изменить (анализ кода):

После

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

в current будет \n, если не достигнут конец файла. После этого вы продолжаете цикл outmost 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;
}

Эта программа, применяемая к себе, исключает все строки комментариев на С++ в ее выходе. Внутренний цикл while не съедает весь текст до конца файла. Обратите внимание на инструкцию putback(c). Без этого новая строка не появится.

Если это не работает для wifstream, это было бы очень странно, за исключением одной причины: когда открытый текстовый файл не сохраняется как 16 бит char, а \n char заканчивается неправильный байт...

Ответ 4

Оберните поток (или его буфер, в частности) в std::streambuf_iterator? Это должно игнорировать все форматирование, а также дать вам хороший интерфейс итератора.

В качестве альтернативы, гораздо более эффективный и надежный подход мог бы просто использовать Win32 API (или Boost) для карты памяти. Затем вы можете пересечь его с помощью простых указателей, и вам гарантировано, что во время выполнения ничего не будет пропущено или преобразовано.

Ответ 5

Извлекители потока ведут себя одинаково и пропускают пробелы.

Если вы хотите прочитать каждый байт, вы можете использовать неформатированные функции ввода, например stream.get(c).

Ответ 6

Почему бы просто не использовать getline?

Вы получите все пробелы, и пока вы не получите символы конца строк, вы все равно будете знать, где они лежат:)

Ответ 7

Вы можете открыть поток в двоичном режиме:

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

Вы потеряете любые операции форматирования, предоставленные моим потоком, если вы это сделаете.

Другой вариант - прочитать весь поток в строке, а затем обработать строку:

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

Конечно, получение строки из ostringstream требует дополнительной копии строки, поэтому вы можете в какой-то момент изменить ее, чтобы использовать пользовательский поток, если вы чувствуете себя авантюрным. EDIT: кто-то еще упоминает istreambuf_iterator, что, вероятно, лучший способ сделать это, чем чтение всего потока в строку.

Ответ 8

Вы можете просто обернуть поток в 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();
            } 

Ответ 9

Просто используйте getline.

while (getline(input,current))
{
      cout<<current<<"\n";

}

Ответ 10

По умолчанию этот флаг пропуска уже установлен для объекта ifstream, поэтому мы должны отключить его. Объект ifstream имеет эти флаги по умолчанию из-за std::basic_ios :: init, вызываемого для каждого нового объекта ios_base (более подробно). Подойдет любое из следующего:

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.