代码之家  ›  专栏  ›  技术社区  ›  dreamlax

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

  •  13
  • dreamlax  · 技术社区  · 15 年前

    我有以下格式的数据:

    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来解析这种格式的数据?

    5 回复  |  直到 15 年前
        1
  •  10
  •   codaddict    11 年前

    你可以在使用前读懂号码 std::getline 从流中读取并存储到 std::string

    int num;
    string str;
    
    while(cin>>num){
        getline(cin,str);
    
    }
    
        2
  •  14
  •   Matthieu N.    14 年前

    这个 C++ String Toolkit Library (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;
    }
    

    可以找到更多示例 Here

        3
  •  9
  •   Jerry Coffin    15 年前

    你已经被告知了 std::getline 但是他们没有提到一个你可能会发现有用的细节:当你打电话 getline ,您还可以传递一个参数,告诉它将哪个字符作为输入的结尾。要读取您的号码,您可以使用:

    std::string number;
    std::string name;
    
    std::getline(infile, number, ':');
    std::getline(infile, name);   
    

    这将把数据放到“:”中 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];
        }
    };
    

    现在,为了使用它,我们将流“嵌入”到一个区域设置中:

    #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;
    }
    

    现在你知道了 为什么? 图书馆的那部分被忽视了。理论上,让标准库为你做工作是很好的——但事实上,大多数时候,你自己做这种工作更容易。

        4
  •  2
  •   Dmitriy    15 年前

    只需使用getline逐行(整行)读取数据并对其进行解析。
    要解析,请使用find_first_of()。

        5
  •  2
  •   N 1.1    15 年前
    int i;
    char *string = (char*)malloc(256*sizeof(char)); //since max is 255 chars, and +1 for '\0'
    scanf("%d:%[^\n]s",&i, string); //use %255[^\n]s for accepting 255 chars max irrespective of input size
    printf("%s\n", string);
    
    

    它的C,也将在C++中工作。scanf提供了更多的控制,但没有错误管理。所以小心使用:)。

    推荐文章