我正在编写简单的OBJ加载器,我遇到了下一个问题 - 我必须从下一个std::string
中提取整数:
f v0/vt0/vn0 v1/vt1/vn0 ... vk/vtk/vnk
其中vk
,vtk
,vnk
是int值,/
和值之间没有空格,组之间只有一个空格。
由于文件可能非常大,而且这种类型的行可能会出现超过100000次,我需要一种有效的方法从字符串中提取整数。
编辑:
正如杰西所说,这是我目前的方法(我假设数据格式正确!):
int p, t, n;
const char* l = line.c_str() + 2;
for (int vIndex = 0; l && sscanf(l, "%d/%d/%d", &p, &t, &n) == 3; ++vIndex)
{
//do something with vertex
l = strchr(l, ' ');
if (l)
{
l += 1;
}
}
答案 0 :(得分:4)
使用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...
}
答案 1 :(得分:2)
std::strtol非常快:
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
}
答案 2 :(得分:2)
使用提升精神,它更强大,并且容易进化。
http://www.boost.org/doc/libs/1_54_0/libs/spirit/doc/html/spirit/qi/tutorials/semantic_actions.html
这是一个通过将顶点放在向量中来解决问题的示例。如果要调用其他函数,请参阅phoenix doc:
我承认Phoenix / Spirit的入门成本很高,但我认为值得痛苦。
#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
答案 3 :(得分:-1)
你可以这样做:
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;
...
}