Если вы хотите использовать специально operator>>
и вы технически не должны использовать строки в частности, вы можете просто сделать пользовательский класс с поведением вы хотите, когда он прочитал в из istream
. Это может быть (в основном) оболочка для строки, с пользовательским поведением при чтении начальных пробелов.
class StringAndNewline{
std::string str_;
friend std::istream& operator>>(std::istream& in, StringAndNewline& str);
public:
StringAndNewline() : str_(){}
StringAndNewline(std::string str) : str_(str){}
const std::string& str() const noexcept {return str_;}
std::string release() {return std::move(str_);}
};
Строка чтения в операторе автоматически игнорирует все preceding whitespace к последовательности непробельных символов, как это определено в настоящей местности. Это поведение, которое вы хотите изменить, и, как оказалось, это легко сделать.
Устранение первоначального пробела обычно выполняется с помощью так называемого сторожевого объекта, который также проверяет, что поток действителен, и устанавливает failbit
потока, если он находится в конце файла. Хотя его поведение по умолчанию заключается в том, чтобы потреблять пробелы, пока не встретится с символом без пробелов, он управляется флагом в его конструкторе, поэтому мы можем использовать эту очень красивую инкапсулированную проверку действительности потока, которую она предлагает.
Перегрузка строки operator>>
выполняет и проверяет часовое устройство, затем считывает до тех пор, пока не встретит пробелы, конец потока или чтение не сработает. Мы можем просто обеспечить, чтобы его часовой никогда не сталкивался с пробелами, занимаясь этим самим.
Таким образом, окончательное чтение в структуру нашего пользовательского класса пользовательские operator>>
будут выглядеть примерно так:
- сделать непробельную еду сторожевой
- проверки часового, возвращая отказавший поток, если он недействителен
- дело с пробелами
- считываются данные, завернутые строки
- возвращение потока
Поскольку мы имеем дело только с символами '\ n' в нашем пробеле, это тоже просто: просто зацикливайтесь, пока поток действителен (если у него заканчивается пробел до достижения любого из наших условий, он устанавливает failbit
, как мы хотел бы) и выйти из цикла, если одно из двух условий - нетто: мы получаем символ новой строки или получаем символ без пробелов. Опять же, приятно просто:
std::istream& operator>>(std::istream& in, StringAndNewline& str){
std::istream::sentry sentry{in, true}; // make a sentry that doesn't eat whitespace
if(!sentry){return in;} // check the sentry
std::locale
presentLocale{}; // get the present locale
char presentChar;
while(in.get(presentChar)){ // while the stream is valid
if(presentChar == '\n'){ // if we get a newline
str.str_ = "\\n"; // set the string to an escaped newline
break; // exit the loop
}
// if we get a non-whitespace character
else if(!std::isspace(presentChar, presentLocale)){
in.unget(); // replace the character in the stream
in >> str.str_; // take advantage of the existing string operator
break; // done with loop
}
}
return in; // return the istream, whatever state it might be in
}
Как только это будет сделано, мы создали оператора ostream для удобства печати:
std::ostream& operator<<(std::ostream& out, const StringAndNewline& str){
return out << str.str();
}
и протестировать наш код:
int main(){
std::istringstream file(
"hello\n"
"world\n"
"C++ is the best tool"
);
StringAndNewline
wordOrNewline;
while(file >> wordOrNewline){
std::cout << wordOrNewline << '\n';
}
}
который печатает этот :
hello
\n
world
\n
C++
is
the
best
tool
только что как мы и хотели! Live on Coliru
Вы даже можете написать оператор строки, если вы действительно хотите легко преобразовать класс оболочки в строки, но я оставлю это вам.
Является ли это проблемой XY? – emlai
Ваш выход не соответствует вашему входу. Существует новая строка между приветствием и миром в файле, как вы его показывали. – NathanOliver
перегрузка строки 'operator >>' [не различает новую строку и другие пробелы] (http://en.cppreference.com/w/cpp/string/basic_string/operator_ltltgtgt), если не существует языковой стандарт, который делает это , но 'getline' делает. В любом случае печать '\ n', а не фактическая новая строка должна быть специальным случаем. Рассматривали ли вы получение каждой строки с getline, преобразовывая полученную строку в 'istringstream', вызывая' operator >> 'на этом, а затем печатаете' \ n' в своей собственной строке, когда поток строк полностью разбирается? – jaggedSpire