C++ 从std::string中提取整数
我正在编写简单的OBJ加载程序,遇到了下一个问题-我必须从nextC++ 从std::string中提取整数,c++,c++11,C++,C++11,我正在编写简单的OBJ加载程序,遇到了下一个问题-我必须从nextstd::string中提取整数: f v0/vt0/vn0 v1/vt1/vn0 ... vk/vtk/vnk 其中,vk,vtk,vnk是int值,/和值之间没有空格,组之间只有一个空格 由于文件可能相当大,并且这种类型的行可能出现100000次以上,因此我需要一种有效的方法来从像这样的字符串中提取整数 编辑: 正如Jesse所问,这是我目前的方法(我假设数据的格式是正确的!): 您可以这样做: if ( sscanf( L
std::string
中提取整数:
f v0/vt0/vn0 v1/vt1/vn0 ... vk/vtk/vnk
其中,vk
,vtk
,vnk
是int值,/
和值之间没有空格,组之间只有一个空格
由于文件可能相当大,并且这种类型的行可能出现100000次以上,因此我需要一种有效的方法来从像这样的字符串中提取整数
编辑:
正如Jesse所问,这是我目前的方法(我假设数据的格式是正确的!):
您可以这样做:
if ( sscanf( Line.c_str(), "%2s %d/%d %d/%d %d/%d %d/%d", Prefix, &A1, &A2, &B1, &B2, &C1, &C2, &D1, &D2 ) == 9 )
{
A3 = B3 = C3 = 0;
...
}
else if ( sscanf( Line.c_str(), "%2s %d/%d/%d %d/%d/%d %d/%d/%d", Prefix, &A1, &A2, &A3, &B1, &B2, &B3, &C1, &C2, &C3 ) == 10 )
{
...
}
else if ( sscanf( Line.c_str(), "%2s %d//%d %d//%d %d//%d", Prefix, &A1, &A3, &B1, &B3, &C1, &C3 ) == 7 )
{
A2 = B2 = C2 = 0;
...
}
else if ( sscanf( Line.c_str(), "%2s %d/%d %d/%d %d/%d", Prefix, &A1, &A2, &B1, &B2, &C1, &C2 ) == 7 )
{
A3 = B3 = C3 = 0;
...
}
使用
std::strtol
,这非常简洁,因为它将返回当前解析的结尾,您可以从那里继续。假设你保证每次读三位数字,像下面的草图一样的东西可以工作
char *p = line.c_str() + 1;
while (p)
{
long v0 = std::strtol(++p, &p, 0); // at the end, p points to '/'
long v1 = std::strtol(++p, &p, 0); // at the end, p points to '/'
long v2 = std::strtol(++p, &p, 0); // at the end, p points to ' '
// On the last one, p will be null...
}
速度相当快:
const char* l = line.c_str() + 2;
while (l)
{
char* c;
long num = std::strtol(l, &c, 10);
if (l == c)
{
break;
}
//do something with vertex
l = c + 1; // move past the slash
}
使用提升精神,它更强大,更容易进化 下面是一个通过将顶点放入向量来解决问题的示例。如果要调用其他函数,请参阅phoenix文档: 我承认菲尼克斯/精神号的入场费很高,但我认为这是值得的
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/home/phoenix/object/construct.hpp>
#include <boost/spirit/home/phoenix/container.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <iostream>
#include <string>
#include <tuple>
typedef std::tuple<double, double, double> vertex;
typedef std::vector<vertex> Vertices;
template <typename Iterator>
bool vector_creator(Iterator first, Iterator last, Vertices& vector)
{
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
namespace phoenix = boost::phoenix;
bool r = qi::phrase_parse(first, last,
(
'f' >> *(qi::double_ >> '/' >> qi::double_>> '/' >> qi::double_)
[
phoenix::push_back(phoenix::ref(vector),
phoenix::construct<vertex>(qi::_1, qi::_2 , qi::_3))
]
), qi::space);
return r;
}
int main()
{
std::string str;
while (getline(std::cin, str))
{
if (str.empty() || str[0] == 'q' || str[0] == 'Q')
{
break;
}
Vertices Vertices;
if (vector_creator(str.begin(), str.end(), Vertices))
{
std::cout << "Parsing succeeded: " << Vertices.size() << std::endl;
}
else
{
std::cout << "Parsing failed." << std::endl;
}
}
return 0;
}
我不认为它比循环字符串和做数学运算更有效。@Jesse,立即假设这个人懒惰是没有多大帮助的。看看他的名声,他已经帮助了很多人,几乎没有懒人的特点。也许他没有时间,或者他不想解决一些问题,而是采取了一种全新的方法。如果你不想帮助他,请跳过这个问题,而不要消极。我不会使用sscanf,效率非常低(一般来说)。@Felics一个简单的有限状态机(FSM)的效率和你将得到的一样高。我只是手工编写代码,因为格式似乎并不复杂,但如果您愿意(例如Ragel),有一些工具可以为您生成FSM代码。@Rob great minds等。错误检查代码在哪里?(您如何知道
std::strtol
读取整数是否失败)@MatthieuM。你不能把一切都给别人!;)有效的注释,因为strtol有一个可怕的界面<代码>标准::stoi更好。但是一定要检查*p='\0'
,因为这是这里的正常终止条件。是否应该l=c+1
移过斜杠?这将一次增加1个字符,转换“vt123”
将产生123、23和3个字符。@Nim,MSalters:谢谢您的反馈。更正。
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/home/phoenix/object/construct.hpp>
#include <boost/spirit/home/phoenix/container.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <iostream>
#include <string>
#include <tuple>
typedef std::tuple<double, double, double> vertex;
typedef std::vector<vertex> Vertices;
template <typename Iterator>
bool vector_creator(Iterator first, Iterator last, Vertices& vector)
{
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
namespace phoenix = boost::phoenix;
bool r = qi::phrase_parse(first, last,
(
'f' >> *(qi::double_ >> '/' >> qi::double_>> '/' >> qi::double_)
[
phoenix::push_back(phoenix::ref(vector),
phoenix::construct<vertex>(qi::_1, qi::_2 , qi::_3))
]
), qi::space);
return r;
}
int main()
{
std::string str;
while (getline(std::cin, str))
{
if (str.empty() || str[0] == 'q' || str[0] == 'Q')
{
break;
}
Vertices Vertices;
if (vector_creator(str.begin(), str.end(), Vertices))
{
std::cout << "Parsing succeeded: " << Vertices.size() << std::endl;
}
else
{
std::cout << "Parsing failed." << std::endl;
}
}
return 0;
}
> a.exe
f 1/1.2/-3 0.5/2.3/0 2./5/6 .3/.2/9888
Parsing succeeded: 4