C++ 如何使用 istringstream 提取混合格式
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/21814297/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to extract mixed format using istringstream
提问by Sunil Kundal
Why does my program not output:
为什么我的程序不输出:
10
1.546
,Apple 1
instead of
代替
10
1
<empty space>
here's my program:
这是我的程序:
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
int main () {
string str = "10,1.546,Apple 1";
istringstream stream (str);
int a;
double b;
string c, dummy;
stream >> a >> dummy >> b >> dummy >> c;
cout << a << endl;
cout << b << endl;
cout << c << endl;
return 0;
}
Basically I am trying to parse the comma-separated strings, any smoother way to do this would help me immense.
基本上我正在尝试解析逗号分隔的字符串,任何更流畅的方法都会对我有很大帮助。
采纳答案by 0x499602D2
In IOStreams, strings (meaning both C-strings and C++ strings) have virtually no formatting requirements. Any and all characters are extracted into a string only until a whitespace character is found, or until the end of the stream is caught. In your example, you're using a string intended to eat up the commas between the important data, but the output you are experiencing is the result of the behavior I just explained: The dummy
string doesn't just eat the comma, but also the rest of the character sequence until the next whitespace character.
在 IOStreams 中,字符串(即 C 字符串和 C++ 字符串)几乎没有格式要求。任何和所有字符都被提取到一个字符串中,直到找到一个空白字符,或者直到捕获到流的末尾。在您的示例中,您正在使用一个字符串来吃掉重要数据之间的逗号,但是您遇到的输出是我刚刚解释的行为的结果:dummy
字符串不仅吃掉了逗号,还吃掉了逗号字符序列的其余部分,直到下一个空白字符。
To avoid this you can use a char
for the dummy variable, which only has space for onecharacter. And if you're looking to put Apple 1
into a string you will need an unformattedextraction because the formatted extractor operator>>()
only reads until whitespace. The appropriate function to use here is std::getline()
:
为避免这种情况,您可以char
对虚拟变量使用 a ,该变量只有一个字符的空间。如果你想Apple 1
放入一个字符串,你将需要一个无格式的提取,因为格式化的提取器operator>>()
只读取空白处。此处使用的适当功能是std::getline()
:
string c;
char dummy;
if ((stream >> a >> dummy >> b >> dummy) &&
std::getline(stream >> std::ws, s))
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
{
}
Clearing the newline after the formatted extraction is also necessary which is why I used std::ws
to clear leading whitespace. I'm also using an if
statement to contain the extraction in order to tell if it succeeded or not.
在格式化提取后清除换行符也是必要的,这就是我过去std::ws
清除前导空格的原因。我还使用一个if
语句来包含提取,以判断它是否成功。
Any smoother way to do this would help me immensely.
任何更顺畅的方式来做到这一点都会对我有很大帮助。
You can set the classification of the comma character to a whitespace character using the std::ctype<char>
facet of the locale imbued in the stream. This will make the use of a dummy variable unnecessary. Here's an example:
您可以使用std::ctype<char>
流中灌输的语言环境的方面将逗号字符的分类设置为空白字符。这将使使用虚拟变量变得不必要。下面是一个例子:
namespace detail
{
enum options { add, remove };
class ctype : public std::ctype<char>
{
private:
static mask* get_table(const std::string& ws, options opt)
{
static std::vector<mask> table(classic_table(),
classic_table() + table_size);
for (char c : ws)
{
if (opt == add)
table[c] |= space;
else if (opt == remove)
table[c] &= ~space;
}
return &table[0];
}
public:
ctype(const std::string& ws, options opt)
: std::ctype<char>(get_table(ws, opt)) { }
};
}
class adjustws_impl
{
public:
adjustws_impl(const std::string& ws, detail::options opt) :
m_ws(ws),
m_opt(opt)
{ }
friend std::istream& operator>>(std::istream& is,
const adjustws_impl& manip)
{
const detail::ctype* facet(new detail::ctype(manip.m_ws, manip.m_opt));
if (!std::has_facet<detail::ctype>(is.getloc())
{
is.imbue(std::locale(is.getloc(), facet));
} else
delete facet;
return is;
}
private:
std::string m_ws;
detail::options m_opt;
};
adjustws_impl setws(const std::string& ws)
{
return adjustws_impl(ws, detail::add);
}
adjustws_impl unsetws(const std::string& ws)
{
return adjustws_impl(ws, detail::remove);
}
int main()
{
std::istringstream iss("10,1.546,Apple 1");
int a; double b; std::string c;
iss >> setws(","); // set comma to a whitespace character
if ((iss >> a >> b) && std::getline(iss >> std::ws, c))
{
// ...
}
iss >> unsetws(","); // remove the whitespace classification
}
回答by 2785528
Allow me to suggest the following.
请允许我提出以下建议。
I don't consider it 'smoother', as cin / cout dialogue is not 'smooth', imho.
我不认为它“更流畅”,因为 cin / cout 对话并不“流畅”,恕我直言。
But I think this might be closer to what you want.
但我认为这可能更接近你想要的。
int main (int, char**)
{
// always initialize your variables
// to value you would not expect from input
int a = -99;
double b = 0.0;
std::string c("");
char comma1 = 'Z';
char comma2 = 'z';
std::string str = "10,1.546,Apple 1";
std::istringstream ss(str);
ss >> a >> comma1 >> b >> comma2;
// the last parameter has the default delimiter in it
(void)getline(ss, c, '\n'); // to get past this default delimiter,
// specify a different delimiter
std::cout << std::endl;
std::cout << a << " '" << comma1 << "' " << std::endl;
std::cout << b << " '" << comma2 << "' " << std::endl;
std::cout << c << std::endl;
return 0;
}
Results: (and, of course, you need not do anything with the commas.)
结果:(当然,你不需要对逗号做任何事情。)
10 ','
1.546 ','
Apple 1
10 ','
1.546 ','
苹果 1
回答by Sunil Kundal
I could manage to change my code a little. Didn't implement 0x499602D2
method yet, but here is what worked for me.
我可以设法稍微更改我的代码。还没有实现0x499602D2
方法,但这是对我有用的方法。
#include <iostream>
#include <string>
#include <cstdlib>
#include <sstream>
using namespace std;
int main () {
string str = "10,1.546,Apple 1";
istringstream stream (str);
int a;
double b;
string c;
string token;
while (getline (stream, token, ',')) {
if (token.find (".") == string::npos && token.find (" ") == string::npos) {
a = atoi (token.c_str ());
} else if (token.find (".") != string::npos) {
b = atof (token.c_str ());
} else {
c = string (token);
}
}
cout << a << endl;
cout << b << endl;
cout << c << endl;
return 0;
}
回答by Nipun Talukdar
You should do the below changes:
您应该进行以下更改:
string str = "10 1.546 Apple 1";
And
和
stream >> a >> b >> dummy >> c;
In your example, dummy would have got the string ",1.546,Apple" . Because till a non-numeric char is encountered, it is fed to variable a. After that everything is added to dummy ( a string ) until the default delimiter (space) is reached
在您的示例中, dummy 会得到字符串 ",1.546,Apple" 。因为直到遇到非数字字符,它才会被馈送到变量 a。之后,所有内容都添加到虚拟(字符串)中,直到达到默认分隔符(空格)