对和字符串流
Posted
技术标签:
【中文标题】对和字符串流【英文标题】:Pairs and stringstream 【发布时间】:2017-02-10 16:10:07 【问题描述】:在previous question 中,我问过我如何读取字符串向量并将其轻松转换为整数或双精度向量。
现在我将简单类型的向量扩展为由冒号分隔的 pairs 类型(考虑 int
、double
甚至 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>>
收到一个std::stringstream
,其中包含一个类似"time:5"
的字符串。操作员需要通过将字符串拆分为两个标记来解析该字符串,然后将第一个标记转换为F
,第二个转换为S
。
执行此操作的一种方法是将std::getline
与自定义分隔符一起使用。你最终会得到两个std::string
令牌。例如,这些可以转换为两个内部std::istringstream
s。
这里有一些代码你可以试试:
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::istringstream
或std::ostringstream
。
【讨论】:
【参考方案2】:因为我是英语新手,所以我不确定理解你想要什么。 我开玩笑说@Christian Hackl 做了什么。所以如果这个答案没有 与您想要的内容有关,请告诉我,我会删除它。
我假设您需要从 string 或 stream 中提取 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
本身的>>
,然后将emplace_back
用于向量,仅此而已。
注意
对于:
如何编写一个 std::stringstream 操作符来解决问题?
我想现在你可以自己做。由于我不确定,所以我没有用operator>>
编写代码。
【讨论】:
以上是关于对和字符串流的主要内容,如果未能解决你的问题,请参考以下文章