简体   繁体   中英

c++ parse int from string pointer

Is there a convenient way to parse an integer from a string::iterator in c++? For this specific question I only care about nonnegative base 10 integers, but all of these solutions can be pretty easily extended to arbitrary integers. Note, unlike similar questions I don't have a reference to the original string, only an iterator, eg

int parse_next_int(std::string::iterator begin, std::string::iterator end) {
    // ...
}

I can think of a number of ways, but none are great. Another note, I'm not declaring stl headers, and I'm assuming everything is done in the std namespace. Hopefully this won't make the examples too difficult to parse.

  1. Allocate a new string, and then call stoi:

     int parse_next_int(string::iterator begin, string::iterator end) { string::iterator num_end = find_if( begin, end, [](char c)->bool{return !isdigit(c);}); string to_parse(begin, num_end); return stoi(to_parse); } 

    The downside of this is that I end up allocating a new buffer for something that could presumably be parsed on the fly.

  2. Treat unsafely as ac string.

     int parse_next_int(std::string::iterator begin, std::string::iterator end) { return atoi(&(*begin)); } 

    This will somewhat work, but if it hits the end of the string and it's not not null terminated (which isn't guaranteed with c++ strings) it will segfault, so while nice and concise, this is probably the worst.

  3. Write it myself:

     int parse_next_int(std::string::iterator begin, std::string::iterator end) { int result = 0; while (begin != end && isdigit(*begin)) { result = result * 10 + (*begin++ - '0'); } return result; } 

    This works and is simple, but it's also heavily problem dependent and not very error tolerant.

Is there some significantly different method that mostly relies on more tolerant stl calls, while still being simple and avoids copying unnecessary buffers?

If you have access to boost you could use:

int parse_next_int(std::string::iterator begin, std::string::iterator end) {
    return boost::lexical_cast<int>(&(*begin), std::distance(begin, end));
}
  1. Create a std::string from the iterators.
  2. Create a std::istringstream from the string .
  3. Extract the integer from the istringstream .

int parse_next_int(std::string::iterator begin, std::string::iterator end) {
   std::string s(begin, end);
   std::istringstream str(s);
   int i;
   str >> i;
   return i;
}

PS Add error handling code to make it production worthy.

Don't use atoi , it causes undefined behaviour if the number would exceed INT_MAX . Your option 3 has the same problem.

My suggestion is:

  1. Find the end of the number, using find_if or strchr or whatever other method; allow for leading - or + if you want.
  2. Null-terminate the substring
  3. Use strtol to convert, with code to handle all the overflow cases.

Regarding the null termination, you could choose one of the following:

  • Copy to an automatic array (easiest option).
  • If end is not actually the end of the string, the write a temporary null terminator there, and restore the old character afterwards.

Note that since C++11, std::string s are guaranteed to be null-terminated, so your dereference-and-treat-as-aC-string solution is not unsafe at all; and, with a comment explaining what's going on, it would have my vote for the best solution to this problem.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM