C++输入流的默认分隔符是空格和回车。在某些场合,输入数据会以其他字符作为分隔符,如‘,’,‘;’等。通常我们可以将数据读入后再处理;STL则提供了一些方法使得我们可以在流这一层面上就进行过滤。
C++的流处理都是与locale(本地化)相关的,每个locale包含了如何处理数值(numeric)、时间和日期(time)、货币(monetary)、字符的分类和转换(ctype)等信息。STL将这样的每个类别称为facet。
现在我们期望输入流能够将自定义的字符如‘,’识别为空格,这属于字符分类的处理。可通过继承STL中的ctype<>来实现自定义的字符分类。代码如下:
//FilterCharacter.h
#include <locale>
{
public:
//chars包含用户自定义的分隔字符
FilterCharacter(const std::string& chars);
std::ctype_base::mask const* getTable(const std::string& chars);
};
{
}
{
std::ctype_base::mask* table = new std::ctype_base::mask[std::ctype<char>::table_size];
std::fill_n(table, std::ctype<char>::table_size, std::ctype_base::mask());
for(int i = 0; i < chars.size(); ++i)
{
//将用户自定义的字符分类为空格
table[chars[i]] = std::ctype_base::space;
}
return table;
}
#include <locale>
class FilterCharacter : public std::ctype<char>
{
public:
//chars包含用户自定义的分隔字符
FilterCharacter(const std::string& chars);
private:
std::ctype_base::mask const* getTable(const std::string& chars);
};
//FilterCharacter.cpp
//这里的true参数指明当FilterCharacter实例被销毁时,自动销毁getTable中生成的table
//也可以为false,表明当该FilterCharacter的引用计数为0时才销毁table
{
}
std::ctype_base::mask
{
std::ctype_base::mask* table = new std::ctype_base::mask[std::ctype<char>::table_size];
std::fill_n(table, std::ctype<char>::table_size, std::ctype_base::mask());
for(int i = 0; i < chars.size(); ++i)
{
//将用户自定义的字符分类为空格
table[chars[i]] = std::ctype_base::space;
}
return table;
}
有了这样一个ctype facet,将其安装到输入流的locale中,就可实现自定义分隔符。来看一个简单应用。
int main()
{
std::string name, age;
FilterCharacter filter(";,");
std::cin.imbue(std::locale(std::locale(), &filter));
std::cout << "name:'" << name << "'\n"
<< "age: '" << age << "'\n";
}
{
std::string name, age;
//将逗号和分号作为分隔符
FilterCharacter filter(";,");
//安装包含有自定义的的ctype的locale到输入流中
std::cin.imbue(std::locale(std::locale(), &filter));
while (std::cin >> name >> age )
std::cout << "name:'" << name << "'\n"
<< "age: '" << age << "'\n";
}
参考资料:
《The C++ Standar Library》