当数据有空格时,用C++的流运算符>>读取格式化数据

dre*_*lax 13 c++ stl stream formatted-input

我有以下格式的数据:

4:How do you do?
10:Happy birthday
1:Purple monkey dishwasher
200:The Ancestral Territorial Imperatives of the Trumpeter Swan

数字可以是1到999之间,字符串最多255个字符.我是C++的新手,似乎有些消息来源建议使用流的>>运算符提取格式化数据,但是当我想提取字符串时,它会停留在第一个空白字符处.有没有办法配置流只停止在换行符或文件结束时解析字符串?我看到有一种getline方法可以提取整行,但是我仍然需要手动将其拆分[有find_first_of],不是吗?

是否有一种简单的方法可以仅使用STL以此格式解析数据?

小智 14

C++字符串工具箱库(StrTk)具有以下问题的解决方案:

#include <string>
#include <deque>
#include "strtk.hpp"

int main()
{
   struct line_type
   {
      unsigned int id;
      std::string str;
   };

   std::deque<line_type> line_list;

   const std::string file_name = "data.txt";

   strtk::for_each_line(file_name,
                        [&line_list](const std::string& line)
                        {
                           line_type temp_line;
                           const bool result = strtk::parse(line,
                                                            ":",
                                                            temp_line.id,
                                                            temp_line.str);
                           if (!result) return;
                           line_list.push_back(temp_line);
                        });

   return 0;
}
Run Code Online (Sandbox Code Playgroud)

更多例子可以在这里找到


cod*_*ict 10

您可以在使用之前读取该数字,该数字std::getline从流中读取并存储到std::string对象中.像这样的东西:

int num;
string str;

while(cin>>num){
    getline(cin,str);

}
Run Code Online (Sandbox Code Playgroud)


Jer*_*fin 9

你已经被告知了std::getline,但是他们没有提到你可能会觉得有用的一个细节:当你打电话时getline,你也可以传递一个参数来告诉它作为输入结束时要处理的字符.要阅读您的电话号码,您可以使用:

std::string number;
std::string name;

std::getline(infile, number, ':');
std::getline(infile, name);   
Run Code Online (Sandbox Code Playgroud)

这会将数据放到':'中number,丢弃':',并将其余部分读入name.

如果你想用来>>读取数据,你也可以这样做,但是它有点困难,并深入研究大多数人从未接触过的标准库区域.流有一个关联locale,用于格式化数字和(重要的)确定什么构成"空白".您可以定义自己的语言环境,将":"定义为空格,将空格("")定义为非空格.告诉流使用该语言环境,它将让您直接读取数据.

#include <locale>
#include <vector>

struct colonsep: std::ctype<char> {
    colonsep(): std::ctype<char>(get_table()) {}

    static std::ctype_base::mask const* get_table() {
        static std::vector<std::ctype_base::mask> 
            rc(std::ctype<char>::table_size,std::ctype_base::mask());

        rc[':'] = std::ctype_base::space;
        rc['\n'] = std::ctype_base::space;
        return &rc[0];
    }
};
Run Code Online (Sandbox Code Playgroud)

现在使用它,我们使用语言环境"灌输"流:

#include <fstream>
#include <iterator>
#include <algorithm>
#include <iostream>

typedef std::pair<int, std::string> data;

namespace std { 
    std::istream &operator>>(std::istream &is, data &d) { 
       return is >> d.first >> d.second;
    }
    std::ostream &operator<<(std::ostream &os, data const &d) { 
        return os << d.first << ":" << d.second;
    }
}

int main() {
    std::ifstream infile("testfile.txt");
    infile.imbue(std::locale(std::locale(), new colonsep));

    std::vector<data> d;

    std::copy(std::istream_iterator<data>(infile), 
              std::istream_iterator<data>(),
              std::back_inserter(d));

    // just for fun, sort the data to show we can manipulate it:
    std::sort(d.begin(), d.end());

    std::copy(d.begin(), d.end(), std::ostream_iterator<data>(std::cout, "\n"));
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

现在您知道为什么图书馆的这一部分被忽略了.从理论上讲,让标准库为你工作是很棒的 - 但事实上,大多数时候,你自己做这种工作更容易.