Forcing a string to an int function to use the entire string

Given the string that should represent the number, I would like to put it in a conversion function that will provide a notification if the entire string is not converted.

To enter: "12" :

  • istringstream::operator>> outputs 12
  • outputs atoi 12
  • stoi exits 12

To enter "1X" I need a rejection response, but I get:

  • istringstream::operator>> outputs 1
  • outputs atoi 1
  • stoi exits 1

To enter "X2" :

  • istringstream::operator>> 0 and sets the error flag
  • atoi outputs 0
  • stoi gives an error

[ Live example ]

Is there a way to trigger a "1X" input error?

+6
source share
2 answers

For a given string str there are several ways to do this, each of which has its advantages and disadvantages. I wrote a live example here: https://ideone.com/LO2Qnq and discussed each of them below:

strtol

As suggested here, the strtol out parameter can be used to get the number of characters read. strtol actually returns long not int so when casting, a cast occurs.

 char* size; const int num = strtol(i.c_str(), &size, 10); if(distance(i.c_str(), const_cast<const char*>(size)) == i.size()) { cout << "strtol: " << num << endl; } else { cout << "strtol: error\n"; } 

Note that i.c_str() is used here to refer to the same line. c_str Returns a pointer to a base array that serves as a symbol repository, not temporary if you have C ++ 11:

c_str() and data() perform the same function

Also note that the pointer returned by c_str will be valid between strtol and distance if:

  • Passing non- const reference to string in any standard library function
  • A non- const function call - members on a string , with the exception of operator[] , at() , front() , back() , begin() , rbegin() , end() and rend()

If any of these cases is violated, you need to make a temporary copy of i that is the basis of const char* and run a test on this.

sscanf

sscanf can use %zn to return the number of characters read, which may be more intuitive than comparing pointers. If the base is important, sscanf may not be a good choice. Unlike stoi and stoi , which support bases 2 - 36, sscanf provides the qualifier only octal ( %o ), decimal ( %d ) and hexadecimal ( %x ).

 size_t size; int num; if(sscanf(i.c_str(), "%d%zn", &num, &size) == 1 && size == i.size()) { cout << "sscanf: " << num << endl; } else { cout << "sscanf: error\n"; } 

stoi

As suggested here, the output parameter stoi works like sscanf %n returning the number of characters read. According to C ++, this takes string and, unlike the C implementations above, stoi throws invalid_argument if the first non-space character is not considered a digit for the current base, and this, unfortunately, means that unlike C implementations, this should check for an error in try and catch blocks.

 try { size_t size; const auto num = stoi(i, &size); if(size == i.size()) { cout << "stoi: " << num << endl; } else { throw invalid_argument("invalid stoi argument"); } } catch(const invalid_argument& /*e*/) { cout << "stoi: error\n"; } 
+3
source

Alternatively, you can use std::istringstream , as you mentioned, but make sure it figured out before the end of the stream. Assuming you have a permalink, you can do something like the following

 T parse(const std::string& input) { std::istringstream iss(input); T result; iss >> result; if (iss.eof() || iss.tellg() == int(input.size())) { return result; } else { throw std::invalid_argument("Couldn't parse entire string"); } } 

The advantage of this approach is that you parse everything that overloads operator>> . Note. I'm not quite sure if this condition is enough, but with my testing it seemed. For some reason, the thread will receive a failure mark if it is resolved to the end.

+1
source

Source: https://habr.com/ru/post/1233152/


All Articles