从std :: string中提取整数

时间:2013-11-14 12:38:51

标签: c++ c++11

我正在编写简单的OBJ加载器,我遇到了下一个问题 - 我必须从下一个std::string中提取整数:

f v0/vt0/vn0 v1/vt1/vn0 ... vk/vtk/vnk

其中vkvtkvnk是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;
    }    
}

4 个答案:

答案 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:

http://www.boost.org/doc/libs/1_55_0/libs/spirit/phoenix/doc/html/phoenix/starter_kit.html#phoenix.starter_kit.lazy_functions

我承认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;
    ...
}