2015-08-28 149 views
-2

如何使用C++ >>操作符來讀取新行?使用流C++讀取換行符

ifstream input("doc.txt".c_str()); 
vector<string> contents; 
while (input >> word) { 
    contents.push_back(word); 
} 

對於文件:

hello 
world 
C++ is the best tool 

應返回

hello 
\n 
world 
\n 
C++ 
is 
the 
best 
tool 

P/S:這是從一個更大的降低的問題。我解析文件的方式導致了這個問題。

+0

這是XY問題嗎? – emlai

+2

您的輸出與您的輸入不符。如您所示,文件中的hello和world之間有一個換行符。 – NathanOliver

+2

'運算符>>'的字符串重載[不能區分換行符和其他空格](http://en.cppreference.com/w/cpp/string/basic_string/operator_ltltgtgt)除非有一個區域設置可以實現,但'getline'確實。在任何情況下,打印'\ n'而不是實際的換行符都必須是特例。你是否考慮過使用getline獲取每一行,將結果字符串轉換爲一個'istringstream',並在其上調用'operator >>',然後在字符串流完全解析時在它自己的行上打印'\ n'? – jaggedSpire

回答

2

您可以使用getline,並且push_back"\n"自己,正如jaggedSpire提到:

ifstream input("doc.txt"); 
vector<string> contents; 
for (string line; getline(input, line);) { 
    istringstream str(line); 
    for (string word; str >> word;) { 
     contents.push_back(word); 
    } 
    contents.push_back("\n"); 
} 
-1

首先,你已經通過的爲const char *在流的構造。其次,流讀者讀取的字符不是空格,這是如何知道何時切入字符串。

通常我們讀取一個二進制文件,讀者知道一個字符告訴我們什麼時候跳過一條着名的\ n但是它與平臺(Win,Unix)的不同。

0

嘗試使用getline(http://www.cplusplus.com/reference/istream/istream/getline/)。 getline將遍歷每行(直到它看到新行字符),並在到達文件結尾時返回0。所以在每次調用getline並打印之後,它都會打印\ n。這裏是你的問題的一個例子,randFile是一個包含文本的隨機文件。

1 #include <iostream> 
    2 #include <fstream> 
    3 int main(){ 
    4 
    5 std::ifstream myFile("randFile", std::ifstream::in); 
    6 char s[BUFSIZ]; 
    7 
    8 while(myFile.getline(s, BUFSIZ)){ 
    9  std::cout << s << std::endl; 
10  std::cout << "\\n"<< std::endl; 
11 } 
12 
13 return 0; 
14 } 
1

如果你正在尋找專門使用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到的非空白字符的序列,由本區域所限定的。這是你想要改變的行爲,事實證明這樣做很簡單。

初始空白的處理通常由稱爲sentry對象的東西執行,該對象還會檢查該流是否有效,並在流的末尾設置流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操作,便於印刷:

​​

和測試我們的代碼:

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

如果你真的想要很容易地將包裝類轉換爲字符串,你甚至可以編寫一個字符串運算符,但我會把它留給你。