c ++ ifstream函数和字段分隔符

时间:2010-11-16 18:35:42

标签: c++ file-io ifstream

对于这个程序,我只使用shell脚本中的数据文件中的字段分隔符。但我试图使用标准库函数ifstream()从数据文件读入。唯一的问题是我得到的数据是这样的

答:KT5:14:执行委员会:

这是针对哈希表的,我需要分离数据结构行中的值以及事务类型。我一直在寻找网络,并没有找到很多关于现场分离器和我发现的相当混乱。

那么问题是,有没有办法用ifstream函数设置字段分隔符,还是我应该使用另一个标准库i / o函数?

感谢。

2 个答案:

答案 0 :(得分:5)

@Steve Townsend已经指出了一种可能性。如果您更喜欢使用operator>>而不是std::getline,那么您也可以这样做。 istream始终将空格视为分隔符。每个流都有一个关联的区域设置,每个区域设置都包含ctype方面。 ctype方面是istream用来确定哪些输入字符是空格的。

在你的情况下,你显然希望流只将换行符和冒号视为“空格”(即分隔符),而实际的空格字符只被视为“普通”字符,而不是分隔符。

要做到这一点,你可以创建一个这样的ctype facet:

struct field_reader: std::ctype<char> {

    field_reader(): std::ctype<char>(get_table()) {}

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

        rc['\n'] = std::ctype_base::space;
        rc[':'] = std::ctype_base::space;
        return &rc[0];
    }
};

要使用此功能,您必须使用此方面使用语言环境“灌输”流:

int main() {
    std::stringstream input("A:KT5:14:executive desk:");

    // have the stream use our ctype facet:
    input.imbue(std::locale(std::locale(), new field_reader()));

    // copy fields from the stream to standard output, one per line:
    std::copy(std::istream_iterator<std::string>(input), 
              std::istream_iterator<std::string>(),
              std::ostream_iterator<std::string>(std::cout, "\n"));
    return 0;
}

然而,我是第一个承认这有一些缺点的人。首先,语言环境和方面通常记录很差,因此大多数 C ++程序员可能会发现这很难理解(尤其是当所有实际工作都发生在“幕后”时,可以这么说) )。

另一种可能性是使用Boost Tokenizer。老实说,这是一个更多工作 - 它需要你做一些事情,比如阅读一个字符串,然后单独分解它。与此同时,它有很好的文档记录,广为人知,并且与人们对如何做这类事情的先入之见相比更适合,尽管有更多的复杂性,但很多人可能会发现它更容易理解。

答案 1 :(得分:4)

getline为您提供了指定分隔符的选项。然后,您可以将来自流的输入读取为由string分隔的_Delim序列:

template<class CharType, class Traits, class Allocator>
   basic_istream< CharType, Traits >& getline(
       basic_istream< CharType, Traits >& _Istr,
       basic_string< CharType, Traits, Allocator >& _Str,
       CharType _Delim
   );

如果这是统一结构化的数据,那么定义一个包含它的结构并实现operator>>从流中加载每个实例可能是有用的,使用操作符代码内部的上述函数。

如果必须处理多行(以便换行是记录分隔符和:字段分隔符),请使用stringstream依次将每一行加载到basic_istream::getline,然后将该行后处理字段如图所示。