流-更改cin的分隔符(C ++)

我已将“ cin”重定向为从文件流中读取cin.rdbug(inF.rdbug())当我使用提取运算符时,它会一直读取直到到达空白字符。

是否可以使用其他定界符? 我通过cplusplus.com中的api,但没有找到任何东西。

yotamoo asked 2020-08-11T22:01:52Z
4个解决方案
42 votes

可以使用:来添加自定义: ::或其他任何:的字间定界符。

如果您正在读取/ 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";
  }
}
Robᵩ answered 2020-08-11T22:02:02Z
20 votes

对于字符串,可以使用std::getline重载来使用其他定界符进行读取。

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

Ben Voigt answered 2020-08-11T22:02:27Z
15 votes

这是对Robᵩ的回答的改进,因为这是正确的选择(我很失望它未被接受。)

您需要做的是更改cin所查看的数组来确定什么是定界符。

在最简单的情况下,您可以创建自己的:

const ctype<char>::mask foo[ctype<char>::table_size] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ctype_base::space};

在我的机器上,cin是10。我已经将数组的该元素设置为定界符值:istream。用':'初始化的ctype仅会在' '上定界,而不是300724320142308308250或'\t'

现在这是一个问题,因为传递给cin的数组不仅定义了定界符,还定义了letter,数字,符号和其他流式传输所需的垃圾。 (Ben Voigt的答案涉及到这一点。)因此,我们真正想要做的是修改istream,而不是从头开始创建一个。

可以这样完成:

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;

初始化为istreamcin将在ctype':'上定界,但不会在' ''\t'上定界。

您可以设置cin或任何其他istream,以使用您的自定义ctype,如下所示:

cin.imbue(locale(cin.getloc(), new ctype<char>(data(bar))));

您还可以在ctypes之间切换,行为会在中途改变:

cin.imbue(locale(cin.getloc(), new ctype<char>(foo)));

如果您需要返回默认行为,只需执行以下操作:

cin.imbue(locale(cin.getloc(), new ctype<char>));

现场例子

Jonathan Mee answered 2020-08-11T22:03:33Z
0 votes

这是对乔恩(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) {}
};

干杯!

Josh C answered 2020-08-11T22:03:57Z
translate from https://stackoverflow.com:/questions/7302996/changing-the-delimiter-for-cin-c