对和字符串流

Posted

技术标签:

【中文标题】对和字符串流【英文标题】:Pairs and stringstream 【发布时间】:2017-02-10 16:10:07 【问题描述】:

在previous question 中,我问过我如何读取字符串向量并将其轻松转换为整数或双精度向量。

现在我将简单类型的向量扩展为由冒号分隔的 pairs 类型(考虑 intdouble 甚至 std::string,所有支持流的类型)的向量.

例子:

time:5, length:10

应该读作std::pair<std::string, unsigned int>,类似这样:

// Here declare what to parse: a string and an uint, separated by a colon
get_vector<std::pair<std::string, unsigned int>>(s);

如何编写一个std::stringstream 操作符来解决问题?

我不知道如何(或者即使)我可以使用getline(我的代码如下)。如果可能的话,我真的很想保留get_vector 函数原样

谢谢!

template <class F, class S>
std::stringstream& operator >> (std::stringstream& in, std::pair<F, S> &out)

    in >> out.first >> out.second;
    return in;


template <class T>
auto get_vector(std::string s) -> std::vector<T>

    std::vector<T> v;

    // Vector of strings
    auto tmp = split(s);

    // Magic
    std::transform(tmp.begin(), tmp.end(), std::back_inserter(v),
                   [](const std::string& elem) -> T
                   
                       std::stringstream ss(elem);
                       T value;
                       ss >> value;
                       return value;
                   );

    return v;

【问题讨论】:

所以在您的代码中elem 将是字符串"time:5, length:10"? 当您说要保留 get_vector 函数的原样时,您的意思是声明而不是定义,对吗? @NathanOliver elem 将是 "time:5",因为原始字符串已被拆分为逗号分隔的组件。 @ChristianHackl 如果可能的话,我希望它保持原样,这就是为什么我认为运营商是必要的。 【参考方案1】:

您的operator&gt;&gt; 收到一个std::stringstream,其中包含一个类似"time:5" 的字符串。操作员需要通过将字符串拆分为两个标记来解析该字符串,然后将第一个标记转换为F,第二个转换为S

执行此操作的一种方法是将std::getline 与自定义分隔符一起使用。你最终会得到两个std::string 令牌。例如,这些可以转换为两个内部std::istringstreams。

这里有一些代码你可以试试:

template <class F, class S>
std::stringstream& operator >> (std::stringstream& in, std::pair<F, S> &out)

    std::string first_token;
    std::string second_token;
    std::getline(in, first_token, ':');
    std::getline(in, second_token);

    std::istringstream first_converter(first_token);
    std::istringstream second_converter(second_token);

    first_converter >> out.first;
    second_converter >> out.second;

    return in;

当字符串中没有':' 时,您可能需要添加一些错误处理。


请注意,如果您不想合并输入和输出,则不应使用std::stringstream。大多数时候,你会想要std::istringstreamstd::ostringstream

【讨论】:

【参考方案2】:

因为我是英语新手,所以我不确定理解你想要什么。 我开玩笑说@Christian Hackl 做了什么。所以如果这个答案没有 与您想要的内容有关,请告诉我,我会删除它。

我假设您需要从 stringstream 中提取 string,然后将它们放入包含 @987654322 的 vector @

假设您有这个字符串也可以作为输入流:std::string string( "one:1, two:20, three:300, four:40000, five:500000" );

有不止一种方法可以做到,但我是这样说的! 所以首先你需要拆分这个字符串,然后把拆分的内容放入vector of pair

std::string string( "one:1, two:20, three:300, four:40000, five:500000" );

std::stringstream io_stream;

std::basic_regex< char > regex( ", " );
std::regex_token_iterator< std::string::const_iterator > last;
std::regex_token_iterator< std::string::const_iterator > first( string.begin(), string.end(), regex, -1 );

std::vector< std::pair< std::string, std::size_t > > vector_of_pair;
std::string str_pair( "" );
std::size_t ui_pair( 0 );

while( first != last )
    io_stream.clear();
    io_stream.seekg( 0 );
    io_stream.seekp( 0 );

    io_stream << *first << '\n';
    std::getline( io_stream, str_pair, ':' );
    // error:
    // no match function to call: stream and int
    // std::getline( io_stream, ui_pair);
    io_stream >> ui_pair;

    vector_of_pair.emplace_back( str_pair, ui_pair );

    ++first;
  

测试

for( std::size_t index = 0; index < vector_of_pair.size(); ++index )
    std::cout << vector_of_pair[ index ].first << " and " << vector_of_pair[ index ].second << '\n';

输出

one and 1
two and 20
three and 300
four and 40000
five and 500000  

工作原理 没有难懂的代码。它只是通过std::regex_token_iterator 拆分字符串,然后在 while 循环中将其值发送到is_stream,然后读取该行并将其发送到str_pair , 但这里因为std::getline 没有提取int 类型的功能,所以我使用stringstream 本身的&gt;&gt;,然后将emplace_back 用于向量,仅此而已。

注意 对于: 如何编写一个 std::stringstream 操作符来解决问题? 我想现在你可以自己做。由于我不确定,所以我没有用operator&gt;&gt; 编写代码。

【讨论】:

以上是关于对和字符串流的主要内容,如果未能解决你的问题,请参考以下文章

字符串流

字符串流数学运算

C++学习50 对字符串流的读写

字符串流有啥意义? [复制]

C中的字符串流

C++:字符串流有啥好处?