我已将 "cin" 重定向为从文件流读取 cin.rdbuf(inF.rdbuf())
。当我使用抽取运算符时,它会一直读取,直到遇到空格字符。
是否可以使用其他分隔符?我查阅了 cplusplus.com 的 API,但没有找到相关内容。
我已将 "cin" 重定向为从文件流读取 cin.rdbuf(inF.rdbuf())
。当我使用抽取运算符时,它会一直读取,直到遇到空格字符。
是否可以使用其他分隔符?我查阅了 cplusplus.com 的 API,但没有找到相关内容。
可以使用 std::ios_base::imbue
添加自定义的 ctype
facet
,从而更改 cin
或任何其他 std::istream
的单词间分隔符。
如果您正在读取类似于 /etc/passwd 的文件,则以下程序将逐个读取每个以 :
分隔的单词。
#include <locale>
#include <iostream>
struct colon_is_space : std::ctype<char> {
colon_is_space() : std::ctype<char>(get_table()) {}
static mask const* get_table()
{
static mask rc[table_size];
rc[':'] = std::ctype_base::space;
rc['\n'] = std::ctype_base::space;
return &rc[0];
}
};
int main() {
using std::string;
using std::cin;
using std::locale;
cin.imbue(locale(cin.getloc(), new colon_is_space));
string word;
while(cin >> word) {
std::cout << word << "\n";
}
}
new
是非常危险的。更不用说你还没有使用 delete
删除你的结构体(而且没有办法删除一个未命名的指针)。因此,在可能的情况下,一定要始终尝试使用 shared_ptr
。 - Earth Enginestd::facet
是一个引用计数指针,std::locale::locale
需要一个原始指针而不是共享指针,并且 std::locale::~locale
被定义为删除 facet 指针。如果您对 locale
接口有问题,请联系标准委员会,而不是我。请参阅 http://en.cppreference.com/w/cpp/locale/locale/locale 上的示例程序。 - Robᵩget_locale
来包装那些带有注释的不寻常使用new
,这样代码审查者就会意识到接口存在问题,而不是代码编写者。这就是我所说的“可控”使用new
的方式。 - Earth Engineunique_ptr<colon_is_space>(new colon is_space).release()
。虽然它基本上与您的代码相同,但更冗长,它表明你正在传递指针所有权。 - Earth Engine对于字符串,您可以使用std::getline
重载函数以使用不同的分隔符进行读取。
对于数字提取,分隔符实际上并不是“空格”,而是任何数字中无效的字符。
istringstream("123_456") >> foo;
或者尝试使用istringstream("123|456") >> foo;
。 - Ben Voigtgetline
并不比整个流慢,但如果性能是您关心的问题,您应该寻找非流选项。" - Jonathan Meectype
查看以确定分隔符的数组。const ctype<char>::mask foo[ctype<char>::table_size] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ctype_base::space};
'\n'
的值为10。我已将数组的该元素设置为分隔符值:ctype_base::space
。使用 foo
初始化的 ctype
仅会在 '\n'
上进行分隔,而不是在 ' '
或 '\t'
上进行分隔。ctype
的数组定义了不仅仅是分隔符,还定义了字母、数字、符号和一些其他流所需的垃圾。(Ben Voigt的答案涉及到了这一点。)所以我们真正想做的是修改一个 mask
,而不是从头开始创建一个。const auto temp = ctype<char>::classic_table();
vector<ctype<char>::mask> bar(temp, temp + ctype<char>::table_size);
bar[' '] ^= ctype_base::space;
bar['\t'] &= ~(ctype_base::space | ctype_base::cntrl);
bar[':'] |= ctype_base::space;
使用bar
初始化的ctype
将在'\n'
和':'
上进行分隔,但不会在' '
或'\t'
上进行分隔。
您可以按照以下方式设置cin
或任何其他istream
以使用您的自定义ctype
:
cin.imbue(locale(cin.getloc(), new ctype<char>(data(bar))));
您还可以在流的中间切换 ctype
,行为将会发生变化:
cin.imbue(locale(cin.getloc(), new ctype<char>(foo)));
cin.imbue(locale(cin.getloc(), new ctype<char>));
bar['\t']
设置为零,可能不是预期的。要清除一个位,请使用 &~
(按位与按位非)。!
是逻辑非,不会产生预期的效果。 - Ben Voigtspace
和cntrl
位,结果不小心把所有东西都去掉了。 - Jonathan Meestruct delimiter_ctype : std::ctype<char> {
static const mask* make_table(std::string delims)
{
// make a copy of the "C" locale table
static std::vector<mask> v(classic_table(), classic_table() + table_size);
for(mask m : v){
m &= ~space;
}
for(char d : delims){
v[d] |= space;
}
return &v[0];
}
delimiter_ctype(std::string delims, ::size_t refs = 0) : ctype(make_table(delims), false, refs) {}
};
干杯!
std::cin
和operator<<
,您是不是想用>>
? - Ben Voigt