C++ 将数字字符串解析为结构向量
我想把一串数字解析成元素向量。字符串由四个数字块组成,用C++ 将数字字符串解析为结构向量,c++,c++11,C++,C++11,我想把一串数字解析成元素向量。字符串由四个数字块组成,用():/分隔,每个块用分隔 具体来说,字符串的格式是:int(int):float/float,请参见下面的代码示例。我想我可以使用正则表达式,但是由于数据是如此结构化,我确信一定有一种更容易接近的方法来解析这样的字符串。我用的是istringstream,但感觉有点笨拙 std::string line = "0(0):0/0;1(2):0.01/0.02;2(4):0.02/0.04;3(6):0.03/0.06;" struct El
():/
分隔,每个块用分隔代码>
具体来说,字符串的格式是:int(int):float/float代码>,请参见下面的代码示例。我想我可以使用正则表达式,但是由于数据是如此结构化,我确信一定有一种更容易接近的方法来解析这样的字符串。我用的是istringstream,但感觉有点笨拙
std::string line = "0(0):0/0;1(2):0.01/0.02;2(4):0.02/0.04;3(6):0.03/0.06;"
struct Element {
int a;
int b;
int c;
int d;
};
std::vector<Element> = parse(line);
std::vector<Element> parse(std::string line)
{
std::vector<Element> elements;
std::istringstream iss(line);
while(iss) {
char dummy;
Element element;
iss >> element.a;
iss.read(&dummy,sizeof(dummy)); // (
iss >> element.b;
iss.read(&dummy,sizeof(dummy)); // )
iss.read(&dummy,sizeof(dummy)); // :
iss >> element.c;
iss.read(&dummy,sizeof(dummy)); // /
iss >> element.d;
iss.read(&dummy,sizeof(dummy)); // ;
if (!iss) {break;}
elements.push_back(element);
}
return elements;
}
std::string line=“0(0):0/0;1(2):0.01/0.02;2(4):0.02/0.04;3(6):0.03/0.06;”
结构元素{
INTA;
int b;
INTC;
int d;
};
std::vector=parse(行);
std::向量解析(std::字符串行)
{
std::向量元素;
标准::istringstream iss(线);
while(国际空间站){
模拟字符;
元素;
iss>>元素a;
iss.read(&dummy,sizeof(dummy));//(
iss>>元素b;
iss.read(&dummy,sizeof(dummy));/)
iss.read(&dummy,sizeof(dummy));/:
iss>>元素c;
iss.read(&dummy,sizeof(dummy));///
iss>>元素d;
iss.read(&dummy,sizeof(dummy));/;
如果(!iss){break;}
元素。推回(元素);
}
返回元素;
}
我的问题是:
什么是解析的好方法?我是否应该使用std::stringstream
并逐个读取数字,然后“切掉”中间的字符?和代码示例中一样
此代码有一个错误,并试图读取一组额外的值,因为在读入最后一个字符后,while(iss)
仍然为真。如何在每次iss>>
之后在不进行测试的情况下终止此循环?或者更一般地说,如何循环从istringstream提取
您的数据结构良好,可以轻松重载运算符>>
从std::ifstream
提取类成员,然后继续从istringstream
或文件流读取它们
下面是一个可能的实现:
#include <iostream>
#include <vector>
#include <string>
#include <sstream>
#include <fstream>
#include <iterator>
#include <stdexcept>
class Element
{
public:
Element() {}
Element(int aa, int bb, float cc, float dd) : a{aa}, b{bb}, c{cc}, d{dd} {}
friend std::istream &operator>> (std::istream &in, Element &e);
friend std::ostream &operator<< (std::ostream &out, Element const &e);
private:
int a;
int b;
float c;
float d;
};
std::istream &operator>> (std::istream &in, Element &e)
{
char delimiter;
if ( not ( in >> e.a >> delimiter and delimiter == '(' and
in >> e.b >> delimiter and delimiter == ')' and
in >> delimiter and delimiter == ':' and
in >> e.c >> delimiter and delimiter == '/' and
in >> e.d >> delimiter and delimiter == ';' )
and not in.eof() )
{
in.setstate(std::ios_base::failbit);
}
return in;
}
std::ostream &operator<< (std::ostream &out, Element const &e)
{
return out << e.a << '(' << e.b << "):" << e.c << '/' << e.d << ';';
}
std::vector<Element> read_Elements_from(std::istream &in)
{
std::vector<Element> tmp (
std::istream_iterator<Element>{in},
std::istream_iterator<Element>{}
);
if ( not in.eof() )
throw std::runtime_error("Wrong format");
return tmp;
}
int main()
{
try
{
using std::cout;
std::istringstream iss {
"0(0):0/0;1(2):0.01/0.2;2(4):0.02/0.04;3(6):0.03/0.06;"
};
auto els_s = read_Elements_from(iss);
cout << "Elements read from the string:\n";
for ( auto const &i : els_s )
{
cout << i << '\n';
}
// assuming a file which lines are similar to the string provided
std::ifstream input_file {"input_data.txt"};
if ( not input_file )
throw std::runtime_error("Can't open input file");
auto els_f = read_Elements_from(input_file);
cout << "\nElements read from the file:\n";
for ( auto const &i : els_f )
{
cout << i << '\n';
}
}
catch ( std::exception const &e )
{
std::cerr << "\nAn unexpected problem cause this application to end:\n\n"
<< e.what() << ".\n\n";
return EXIT_FAILURE;
}
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
类元素
{
公众:
元素(){}
元素(int-aa,int-bb,float-cc,float-dd):a{aa},b{bb},c{cc},d{dd}
friend std::istream&operator>>(std::istream&in,Element&e);
friend std::ostream&operator>(std::istream&in,Element&e)
{
字符分隔符;
如果(不是)(在>>e.a>>中)分隔符和分隔符=='('和
在>>e.b>>中,分隔符和分隔符==')'和
在>>中,分隔符和分隔符==':'和
在>>e.c>>中,分隔符和分隔符=='/'和
在>>e.d>>中,分隔符和分隔符==';')
而不是在.eof()中)
{
in.setstate(std::ios_base::failbit);
}
返回;
}
std::ostream&operator1*sizeof(char)
保证为1。在表达式1*sizeof(char)
中,值1
是一个幻数,似乎是指伪和sizeof(char)中的字符数
似乎指的是dummy
的类型。如果出于表达性或可维护性而选择不提供常量1,为什么不直接使用sizeof(dummy)
?当前表单并不比直接提供1更好。验证字符串的格式是否重要,或者是否知道它是正确的?如果已知它是有效的,您可以简单地在任何非数字字符序列上标记整个字符串。您将得到一个数字列表,从中可以很容易地构造Element
。您是否想过序列化程序?读取数据结构是一个常见的问题,通常是一个常见的解决方案。感谢您对1*sizeof(char)的评论
。还使parse
函数返回std::vector
。我将研究boost/tokenizer,看看能做什么。@Klaus,你能推荐一个特定的序列化程序吗?最好,序列化的数据应该是文本,而不是二进制的,即人类可读的。非常酷,非常感谢这个例子。这很好用,非常好ks相当完整!