0

Let us say that we are reading a float with std::cin or from a file, and want to enforce the condition that it has two trailing decimal places:

E.g.
4.01 (valid)
4.001 (invalid - has three trailing decimal places)
a,47 (invalid, has two non [0-9] characters in 'a' and ',')
#556.53 (invalid, has '#')

(Just for context, in my example, I am parsing from a text file with several entries separated by spaces, validating each input, and storing them in a struct for further processing.)

How do we do it?

kakrafoon
  • 476
  • 5
  • 13
  • 1
    You don't mention the language you're using. But this sounds like a job for regular expressions. Something like `\d+\.\d{2}` – Bob Kaufman Jan 27 '16 at 23:33
  • C++ has regexes these days. Are you insisting that the values have exactly two decimal fraction digits, or at most two? – rici Jan 28 '16 at 00:10
  • I am insisting that it has exactly two decimal places. – kakrafoon Jan 28 '16 at 00:18

2 Answers2

0

I found this from other sources in stackoverflow.

C++ How to check an input float variable for valid input

Here is the implementation. We read as string and only accept if any of the characters not digits (in perl, I suppose we could simply do a regex non-match [0-9]).

Apparently, the find_first_not_of method in string does this for us:

  std::string a;

  if(!(std::cin>>a)){
    std::cout << "Invalid float entry " << std::endl;
  }

  if(a.find_first_not_of("1234567890.-")!=std::string::npos){
    std::cout << "Invalid string to float" << std::endl;}

Next, we verify that the string has two decimal places by searching for the location of the decimal point.

  if(a.size()-a.find(".")!=3){
    std::cout << "Valid float but must have two decimal places \n";
  }else{
    std::cout << "Accept - valid float and has two decimal places \n";
  }

Finally, we convert to float using stof.

float u = stof(a);
Community
  • 1
  • 1
kakrafoon
  • 476
  • 5
  • 13
0

If you have a C++ compiler and standard library which implement C++11, then you can use a regular expression, which is very simple:

#include <iostream>
#include <regex>
#include <string>

int main(int argc, char** argv) {
    std::string pattern("[-+]?\\d+\\.\\d\\d$");
    std::regex reg(pattern);
    for (int i = 1; i < argc; ++i) {
      std::cout << argv[i]
                << (std::regex_match(argv[i], reg) ? " matched\n" : " didn't match\n");
    }
    return 0;
}

That test program takes the values as arguments rather than reading them from a file or stream, but modifying it to use the istream is trivial. There is no need to convert the string to a C-string; the first argument to regex_match can also be a std::string, or it can even be a pair of iterators whose value_type is char. In this case it just happened to be convenient to use a char*.

See it live on coliru.

rici
  • 234,347
  • 28
  • 237
  • 341