C++ 从istream读取格式化输入

C++ 从istream读取格式化输入,c++,C++,下面的问题已从实际需求中简化 考虑以下计划: #include <iostream> #include <iterator> #include <string> #include <set> #include <algorithm> using namespace std; typedef string T; // to simplify, always consider T as string template<typen

下面的问题已从实际需求中简化

考虑以下计划:

#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;
}
#包括
#包括
#包括
#包括
#包括
使用名称空间std;
typedef字符串T;//为了简化,总是把T当作字符串。
模板
void do_something(常量输入迭代器&first,常量输入迭代器&last){
常量ostream_迭代器os(cout,“\n”);
常量集合词(第一个、最后一个);
复制(words.begin()、words.end()、os);
}
int main(int argc,字符**argv){
常量istream_迭代器为(cin),eof;
做某事(是,eof);
返回0;
}
该程序从
istream
cin
)中提取所有单词,并对它们进行处理。默认情况下,每个单词都用空格分隔。格式化提取背后的逻辑在
istream\u迭代器中


我现在需要做的是将两个迭代器传递到
do_something()
以便提取的单词将由标点字符而不是空格分隔(空格将被视为“正常”字符)。你会怎样用“干净的C++方式”(即,最小的努力)?

尽管它不是先验的显而易见的,但是有一个相对简单的方式来改变流被认为是空白的内容。这样做的方法是:<代码> IMBUEE()>代码>流,使用<代码> STD::LoalAs//Cord>对象,其<代码> STD::cType < /Cord>刻面被替换为将所需字符视为空白。code>imbue()
locale
ctype
-嗯?!?好吧,这些不一定是你每天使用的东西,所以这里有一个快速的例子,它设置
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) {}
};
请注意,这实际上只将
\n
视为空格字符。这也意味着不会跳过其他字符作为空白。。。当然,多个逗号字符的序列被认为只是一个分隔符,而不可能创建一组空字符串。还要注意,上面的
std::ctype
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];
};
模板
结构commactype_base{
commactype_base():表{
std::transform(std::ctype::classic_table(),
std::ctype::classic_table()+std::ctype::table_size,
这个->表,
[](std::ctype_base::mask m)->std::ctype_base::mask{
返回m&~(std::ctype_base::space);
});
这->表u[static_cast(S0)]|=std::ctype_base::space;
这->表u[static_cast(S1)]|=std::ctype_base::space;
}
std::ctype::mask table_[std::ctype::table_size];
};

遗憾的是,这与我在系统上使用的gcc版本(显然是
std::ctype::classic_table()相冲突)
生成一个空指针。使用当前版本的clang编译此代码不起作用,因为clang不支持lambda。有两个警告,上面的代码应该是正确的,不过…

我不知道表的其余部分在哪里填充了默认值……这会不会破坏所有非空格字符类型?@Ben Voigt:我喜欢我的代码可能是正确的,但幸运的是:微妙的关键是
:table_uz()
用默认的类型掩码填充表格?很好,但是通常的空白字符仍然被标记为空格,因为您没有更改它们。等等,我不确定。
ctype::mask
char
的类型定义,所以所有值都初始化为零。这清除了“spaciness”通常的空白字符,但它也打破了所有其他ctype类别。没有字符会被测试为
上限
下限
数字
xdigit
,等等。默认掩码为空。我创建了一个空掩码表,并将表中的两个条目设置为空格。使用这个特殊的
std::ctype
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];
};