更改cin的分隔符(c ++)

yot*_*moo 42 c++ whitespace stream cin delimiter

我已经重定向"cin"来从文件流中读取cin.rdbug(inF.rdbug()) 当我使用提取操作符时,它会读取它直到它到达空格字符.

是否可以使用另一个分隔符?我在cplusplus.com上浏览了api,但没有找到任何东西.

Rob*_*obᵩ 42

使用添加自定义可以更改字间分隔符cin或任何其他分隔符.std::istreamstd::ios_base::imbuectype facet

如果您正在以/ 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";
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 这通常是很好的建议,不适用于这种特殊情况.在这种情况下,`std :: facet`是一个引用计数指针,`std :: locale :: locale`需要一个原始指针,而不是一个共享指针,并且`std :: locale ::〜locale`被定义为`删除`facet指针.如果你对`locale`的界面有问题,请与标准委员会讨论,而不是我.请参阅http://en.cppreference.com/w/cpp/locale/locale/locale上的示例程序 (23认同)
  • 如果不创建新函数,表示所有权转移的更好方法可能是`unique_ptr <colon_is_space>(new colon is_space).release()`.虽然它与您的代码基本相同但更详细,但它表示您正在传输指针所有权. (5认同)
  • 即使我建议定义一个包装函数`get_locale`来包含对注释的'new`的不寻常使用.所以代码审查者会意识到界面有问题,而不是代码编写者.这就是我所谓的"控制"使用"新"的方式. (3认同)

Ben*_*igt 20

对于字符串,您可以使用std::getline重载来使用不同的分隔符进行读取.

对于数字提取,分隔符实际上不是"空白",而是数字中无效的任何字符.


Jon*_*Mee 15

这是Robᵩ的答案的改进,因为这是正确的(我很失望,它没有被接受.)

您需要做的是更改ctype查看的数组以确定分隔符是什么.

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

const ctype<char>::mask foo[ctype<char>::table_size] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ctype_base::space};
Run Code Online (Sandbox Code Playgroud)

在我的机器上'\n'是10.我已将数组的元素设置为分隔符值:ctype_base::space.一个ctype与初始化foo只会划上'\n'没有' ''\t'.

现在这是一个问题,因为传入的数组ctype定义的不仅仅是分隔符,还定义了leters,数字,符号和流式传输所需的其他垃圾.(Ben Voigt的答案触及了这一点.)所以我们真正想做的是修改 a 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;
Run Code Online (Sandbox Code Playgroud)

一个ctype与初始化bar将划上'\n'':',但不会' '还是'\t'.

您可以像以下一样设置cinistream使用您的自定义ctype:

cin.imbue(locale(cin.getloc(), new ctype<char>(data(bar))));
Run Code Online (Sandbox Code Playgroud)

你也可以在ctypes 之间切换,行为将在中途改变:

cin.imbue(locale(cin.getloc(), new ctype<char>(foo)));
Run Code Online (Sandbox Code Playgroud)

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

cin.imbue(locale(cin.getloc(), new ctype<char>));
Run Code Online (Sandbox Code Playgroud)

Live example


Jos*_*h C 5

这是对 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) {}
};
Run Code Online (Sandbox Code Playgroud)

干杯!