Использование istringstream с 26-символьным символом ASCII

У меня есть довольно простой вопрос, но я нигде не смог найти никакой помощи, поэтому я надеялся на некоторую помощь. Я работаю с некоторыми строковыми потоками С++, и у меня есть строковые данные, которые вызывают сбой моего потока. В частности, поток терпит неудачу, когда я встречаю символ Ctrl-Z (26 или 0x1A), что не особенно удивительно.

Начнем с того, что у меня есть строка данных, представляющая изображение, в том смысле, что каждый байт (или символ) строки представляет некоторое значение RGB изображения где-то (точная структура изображения не имеет значения). Из этой строки я хочу восстановить изображение значений RGB, которые она представляет. Подход, который я использовал, состоял в том, чтобы преобразовать строку в поток строк, чтобы я мог лучше анализировать данные, поскольку начальные байты содержат информацию заголовка, которая мне нужна.

Это выглядит примерно так:

std::string data = getImageData(); // Get the image from somewhere
std::istringstream ss(data);
char byte = ' ';
while (ss.get(byte)) {
   // PROCESS THE BYTE
}

Это работает просто отлично, пока он неизбежно не достигает какого-то байта со значением ASCII 26, который обычно является маркером EOF, и поток выбрасывает свои флаги и помечает его как сбой. Как только это происходит, поток завершается, и я больше не могу читать данные из потока. Мне было интересно, как я могу обойти эту ошибку и продолжать читать, пока поток не станет пустым.

Что я сделал/исследовал

Строка data находится вне моего контроля. Я не могу изменить то, что это такое, но теоретически я мог бы изменить его значения после того, как я его извлек, поскольку это копия исходных данных изображения. В общем, предполагается, что это данные изображения в определенном формате, поэтому за его заголовком значения байтов могут быть любыми, даже ASCII 26.

Многие предложения, которые я видел, говорят открывать поток с помощью std::ios::binary, но это тоже не работает. Дальнейшие исследования показывают, что этот режим не существует для строковых потоков, но существует для файловых потоков. Теоретически, если бы данные поступали из файлового потока, а не из строкового потока, проблем бы не было. К сожалению, опять же, данные должны поступать в виде строки, поэтому я не могу это контролировать. Оттуда я просто не знаю, есть ли способ прочитать строковый поток как настоящий двоичный файл, и я просто не могу понять это.

Большой вопрос заключается в следующем: есть ли способ читать отдельные байты из строкового потока в двоичном режиме, чтобы символ ASCII 26 не вызывал проблем, или есть лучший способ управлять строкой data в первую очередь по мере ее поступления? чтобы это не было проблемой?

Спасибо за чтение!


person Josh B.    schedule 02.03.2021    source источник
comment
Интересно, что я не могу воспроизвести вашу проблему ни с Visual Studio в Windows, ни в Linux. Вы уверены, что ваш анализ правильный? Я попытался установить data непосредственно в строку "abc\032def" (встроенный ascii 26), и чтение потока не останавливается посередине. Может быть, уже data усекается на 26-м символе? Или что тело цикла заканчивается на этом символе? В любом случае кажется, что вы можете использовать строку напрямую, а не через поток (как предлагается в одном из ответов).   -  person Daniel Junglas    schedule 02.03.2021
comment
@DanielJunglas Похоже, что использование строки напрямую может быть предпочтительнее. Поправьте меня, если я ошибаюсь; не является ли \0 нулевым символом ASCII 0? Столкнулся с проблемой замены персонажа.   -  person Josh B.    schedule 02.03.2021
comment
@ДжошБ. \032 является восьмеричным 32, то есть десятичным 26.   -  person dxiv    schedule 02.03.2021
comment
@dxiv Ой! Виноват. Спасибо!   -  person Josh B.    schedule 02.03.2021


Ответы (1)


Я предлагаю вообще избегать использования std::istringstream. Поскольку вы, кажется, работаете с одним символом за раз, просто перебирайте строку и обрабатывайте каждый символ по своему усмотрению.

std::string data = getImageData();
for (char ch : data)
{
   // Use ch
}
person R Sahu    schedule 02.03.2021
comment
Или, если хранилище представляет собой обычный массив символов, просто for (int i = 0; data[i]; i++) { ... } - person David C. Rankin; 02.03.2021
comment
Похоже, что можно использовать обычную строку. Тогда из любопытства, поскольку я наивен, какое преимущество имеет stringstream перед обычной строкой? Предлагает ли он просто лучшее средство, если бы мы считывали данные из сети или что-то подобное? Потому что из этого кажется, что синтаксический анализ строкового потока просто оставит нам головную боль. - person Josh B.; 02.03.2021
comment
@ДжошБ. если вы ожидаете получить строку, которая может содержать числа, которые вам нужно прочитать, то будет хорошо использовать istringstream. Вы не хотите писать код для разбора входящей строки в своем приложении. Пусть istringstream позаботится об этом за вас. - person R Sahu; 02.03.2021
comment
@RSahu Потрясающе, большое спасибо! - person Josh B.; 02.03.2021