13

我有以下格式的数据:

4:你好吗?
10:生日快乐
1:紫猴洗碗机
200:小号天鹅的祖先领土命令

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

有没有一种简单的方法可以只使用 STL 来解析这种格式的数据?

4

5 回答 5

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

更多示例可以在这里找到

于 2010-12-30T20:12:41.713 回答
10

您已经听说过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;
}

现在你知道为什么图书馆的那部分如此被忽视了。从理论上讲,让标准库为您完成工作是很棒的——但实际上,在大多数情况下,您自己做这种工作会更容易。

于 2010-02-26T16:27:33.553 回答
10

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

int num;
string str;

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

}
于 2010-02-26T01:16:12.520 回答
2
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 提供更多控制,但没有错误管理。所以谨慎使用:)。

于 2010-02-26T01:09:20.037 回答
2

只需使用 getline 逐行(整行)读取数据并解析即可。
解析使用 find_first_of()

于 2010-02-26T01:18:03.770 回答