更改 cin (c++) 的分隔符
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/7302996/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
changing the delimiter for cin (c++)
提问by yotamoo
I've redirected "cin" to read from a file stream cin.rdbug(inF.rdbug())
When I use the extraction operator it reads until it reaches a white space character.
我已重定向“cin”以从文件流中读取cin.rdbug(inF.rdbug())
当我使用提取运算符时,它会一直读取直到遇到一个空白字符。
Is it possible to use another delimiter? I went through the api in cplusplus.com, but didn't find anything.
是否可以使用其他分隔符?我浏览了 cplusplus.com 中的 api,但没有找到任何东西。
回答by Rob?
It is possible to change the inter-word delimiter for cin
or any other std::istream
, using std::ios_base::imbue
to add a custom ctype
facet
.
可以更改cin
或任何其他的字间分隔符std::istream
,std::ios_base::imbue
用于添加自定义.ctype
facet
If you are reading a file in the style of /etc/passwd, the following program will read each :
-delimited word separately.
如果您正在读取 /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";
}
}
回答by Ben Voigt
For strings, you can use the std::getline
overloads to read using a different delimiter.
对于字符串,您可以使用std::getline
重载以使用不同的分隔符进行读取。
For number extraction, the delimiter isn't really "whitespace" to begin with, but any character invalid in a number.
对于数字提取,分隔符并不是真正的“空格”开始,而是数字中的任何无效字符。
回答by Jonathan Mee
This is an improvement on Rob?'s answer, because that is the right one (and I'm disappointed that it hasn't been accepted.)
这是对Rob的改进?的答案,因为那是正确的(我很失望它没有被接受。)
What you need to do is change the array that ctype
looks at to decide what a delimiter is.
您需要做的是更改ctype
查看以确定分隔符是什么的数组。
In the simplest case you could create your own:
在最简单的情况下,您可以创建自己的:
const ctype<char>::mask foo[ctype<char>::table_size] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ctype_base::space};
On my machine '\n'
is 10. I've set that element of the array to the delimiter value: ctype_base::space
. A ctype
initialized with foo
would only delimit on '\n'
not ' '
or '\t'
.
在我的机器上'\n'
是 10。我已将数组的该元素设置为分隔符值:ctype_base::space
。一个ctype
与初始化foo
只会划上'\n'
没有' '
或'\t'
。
Now this is a problem because the array passed into ctype
defines more than just what a delimiter is, it also defines leters, numbers, symbols, and some other junk needed for streaming. (Ben Voigt's answer touches on this.) So what we really want to do is modifya mask
, not create one from scratch.
现在这是一个问题,因为传入的数组ctype
不仅定义了分隔符,它还定义了字母、数字、符号和其他一些流所需的垃圾。(Ben Voigt的回答触及了这一点。)所以我们真正想做的是修改一个mask
,而不是从头开始创建一个。
That can be accomplished like this:
这可以像这样完成:
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;
A ctype
initialized with bar
would delimit on '\n'
and ':'
but not ' '
or '\t'
.
一个ctype
与初始化bar
将划上'\n'
和':'
,但不会' '
还是'\t'
。
You go about setting up cin
, or any other istream
, to use your custom ctype
like this:
您开始设置cin
或任何其他istream
,以使用您的自定义,ctype
如下所示:
cin.imbue(locale(cin.getloc(), new ctype<char>(data(bar))));
You can also switch between ctype
s and the behavior will change mid-stream:
您还可以在ctype
s之间切换,行为将在中途改变:
cin.imbue(locale(cin.getloc(), new ctype<char>(foo)));
If you need to go back to default behavior, just do this:
如果您需要返回默认行为,只需执行以下操作:
cin.imbue(locale(cin.getloc(), new ctype<char>));
回答by Josh C
This is an improvement on Jon's answer, and the example from cppreference.com. So this follows the same premise as both, but combines them with parameterized delimiters.
这是对 Jon 的回答以及来自cppreference.com的示例的改进。所以这遵循与两者相同的前提,但将它们与参数化分隔符结合起来。
struct 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) {}
};
Cheers!
干杯!