改变cin的定界符(c++)

时间:2022-09-23 00:09:44

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,但是什么也没找到。

3 个解决方案

#1


33  

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.

使用std::ios_base::imbue添加一个自定义的ctype facet,可以更改cin或任何其他std::istream。

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

#2


17  

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.

对于数字提取,分隔符并不是真正的“空白”,而是一个数字中的任何字符无效。

#3


14  

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::空格。用foo初始化的ctype只对'\n' not '或'\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 modify a mask, not create one from scratch.

这是一个问题,因为传入ctype的数组定义的不仅仅是分隔符,它还定义了字符串、数字、符号,以及流所需的其他垃圾。(Ben Voigt的回答涉及到这一点。)因此,我们真正想做的是修改一个掩码,而不是从头创建一个。

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'.

用bar初始化的ctype将在'\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>(bar.data())));

You can also switch between ctypes and the behavior will change mid-stream:

您还可以在ctypes之间切换,行为将在中间流中切换:

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

[Live example]

(生活的例子)

#1


33  

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.

使用std::ios_base::imbue添加一个自定义的ctype facet,可以更改cin或任何其他std::istream。

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

#2


17  

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.

对于数字提取,分隔符并不是真正的“空白”,而是一个数字中的任何字符无效。

#3


14  

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::空格。用foo初始化的ctype只对'\n' not '或'\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 modify a mask, not create one from scratch.

这是一个问题,因为传入ctype的数组定义的不仅仅是分隔符,它还定义了字符串、数字、符号,以及流所需的其他垃圾。(Ben Voigt的回答涉及到这一点。)因此,我们真正想做的是修改一个掩码,而不是从头创建一个。

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'.

用bar初始化的ctype将在'\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>(bar.data())));

You can also switch between ctypes and the behavior will change mid-stream:

您还可以在ctypes之间切换,行为将在中间流中切换:

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

[Live example]

(生活的例子)