繁体   English   中英

从istream读取格式化输入

[英]Reading formatted input from an istream

以下问题已从实际要求中简化。

考虑以下程序:

#include <iostream>
#include <iterator>
#include <string>
#include <set>
#include <algorithm>

using namespace std;

typedef string T; // to simplify, always consider T as string

template<typename input_iterator>
void do_something(const input_iterator& first, const input_iterator& last) {
    const ostream_iterator<T> os(cout, "\n");
    const set<T> words(first, last);
    copy(words.begin(), words.end(), os);
}

int main(int argc, char** argv) {
    const istream_iterator<T> is(cin), eof;
    do_something(is, eof);
    return 0;
}

该程序从istreamcin )中提取所有单词并对它们执行某些操作。 默认情况下,每个单词都由一个空格分隔。 格式化提取背后的逻辑在istream_iterator

我现在需要做的是传递do_something()两个迭代器,以便提取的单词将用标点符号而不是空格分隔(白色空格将被视为“普通”字符)。 您将如何以“干净的C ++方式”(即尽可能少的努力)做到这一点?

虽然它不是先验明显的,但是有一种相对简单的方法可以改变流认为是空白的内容。 执行此操作的方法是使用std::locale对象imbue()来替换std::ctype<char> facet以将所需字符视为空格。 imbue()localectype - 呵呵?!? 好吧,好吧,这些不一定是你日常使用的东西所以这里是一个快速的例子,它设置了std::cin以逗号和换行符号作为间隔使用:

#include <locale>
template <char S0, char S1>
struct commactype_base {
    commactype_base(): table_() {
        this->table_[static_cast<unsigned char>(S0)] = std::ctype_base::space;
        this->table_[static_cast<unsigned char>(S1)] = std::ctype_base::space;
    }
    std::ctype<char>::mask table_[std::ctype<char>::table_size];
};
template <char S0, char S1 = S0>
struct ctype:
    commactype_base<S0, S1>,
    std::ctype<char>
{
    ctype(): std::ctype<char>(this->table_, false) {}
};

实际上, std::ctype<char>这个特定实现实际上可以用来使用一个或两个任意char作为空格(适当的C ++ 2011版本可能允许任意数量的参数;另外,不要真的必须是模板论证)。 无论如何,有了这个,只需在main()函数的开头放下以下行,就可以了:

std::cin.imbue(std::locale(std::locale(), new ::ctype<',', '\n'>));

请注意,这真的只考虑,并且\\n为空格字符。 这也意味着不会跳过任何其他字符作为空格。 ...当然,一系列多个逗号字符被认为只是一个分隔符,而不是可能创建一堆空字符串。 另请注意,上面的std::ctype<char> facet会删除所有其他字符分类。 如果要解析除了字符串之外的其他对象,您可能希望保留其他字符分类,并仅更改空格。 这是一种可以做到的方法:

template <char S0, char S1>
struct commactype_base {
    commactype_base(): table_() {
        std::transform(std::ctype<char>::classic_table(),
                       std::ctype<char>::classic_table() + std::ctype<char>::table_size,
                       this->table_, 
                       [](std::ctype_base::mask m) -> std::ctype_base::mask {
                           return m & ~(std::ctype_base::space);
                       });
        this->table_[static_cast<unsigned char>(S0)] |= std::ctype_base::space;
        this->table_[static_cast<unsigned char>(S1)] |= std::ctype_base::space;
    }
    std::ctype<char>::mask table_[std::ctype<char>::table_size];
};

遗憾的是,这与我在我的系统上的gcc版本崩溃了(显然std::ctype<char>::classic_table()产生一个空指针。用当前版本的clang编译它不起作用,因为clang没有' t支持lambda。有了两个警告,上面的代码应该是正确的,尽管......

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM