0

I would like to check if a decimal number adheres to a predefined standard. I have used the following regular expression ^[+-]?[0-9]+(.[0-9]{2,4})$ , but it does not seem to work in C++. I have tried numerous regex verification solutions and it works there as intended. For example if I have the number 0.00000, the output should be false, on the other hand if the number is 0.00, the output should be true. In my case the output just seems not to detect any. This is my source code, can you please help? Thank you.

void detectFormatConsistency()
{
    std::regex dbl("^[+-]?[0-9]+(\\.[0-9]{2,4})$");
    std::smatch matches;
    int detected = 0;
    for(unsigned int index = 0; index < mixedDistro.size(); index++)
    {
        double currentValue = mixedDistro[index];
        std::string test = std::to_string(currentValue);
        if(std::regex_search(test, dbl)) \\I also tried with match
        {
            detected++;
        }
    }
    printf("Number of points detected: %d\n", detected);
}

UPDATE: The following source code now works as intended:

void detectFormatConsistency()
{
    std::regex dbl("^[+-]?[0-9]+(\\.[0-9]{2,4})$");
    std::smatch matches;
    int detected = 0;
    for(unsigned int index = 0; index < mixedDistro.size(); index++)
    {
        double currentValue = mixedDistro[index];
        std::string test = tostring(currentValue);
        if(std::regex_match(test, dbl))
        {
            detected++;
        }
    }
    printf("Number of points detected: %d\n", detected);
}



  //https://stackoverflow.com/questions/13686482/c11-stdto-stringdouble-no-trailing-zeros     
  //Thanks to: @Silencer
    template<typename T>
    std::string tostring(const T &n) {
        std::ostringstream oss;
        oss << n;
        std::string s =  oss.str();
        unsigned int dotpos = s.find_first_of('.');
        if(dotpos!=std::string::npos){
             unsigned int ipos = s.size()-1;
            while(s[ipos]=='0' && ipos>dotpos){
                --ipos;
            }
            s.erase ( ipos + 1, std::string::npos );
        }
        return s;
    }

Thank you all for helping!

  • 1
    Nothing in your regex prevents `0.0000` to match. It follows the pattern, having one `0` before `.` and 4 following. `0.00` can't match on the other side, as being followed by only 2 `0` whereas the regex in your code claims for at least 3. – PJProudhon Jun 21 '18 at 14:54
  • I would check `mixedDistro` values. All values in this array `double vals[] = {0.00, 0.0000, 0.0, 0 };` are converted to `0.000000` by `std::to_string`. – sardok Jun 21 '18 at 15:07
  • You should use `std::regex_match` because `std::regex_search` matches any substring. – Galik Jun 21 '18 at 15:10
  • Also the regex in your question is different from the regex in your code and **both** of them allow the pattern you say should be rejected... – Galik Jun 21 '18 at 15:13
  • *"I have tried numerous regex verification solutions and it works there as intended."* - can you provide one so we can compare? – Galik Jun 21 '18 at 15:14
  • https://regexr.com/ ; https://regex101.com/ @Galik these are the resources that I used. The difference between both comes that in C++ I need to escape ".", as with one "\" the code compiles with warning: "warning: unknown escape sequence: '\.' " Thus I have added the second "\" in the code. https://stackoverflow.com/questions/13842038/c-regex-escaping-punctional-characters-like Thanks all for your help! – Milen Marev Jun 21 '18 at 15:33
  • In your question you say: *"0.0000, the output should be false"* but on the regex test site you gave me the output is **true** for the regex in your code: https://regex101.com/r/1txILJ/1 – Galik Jun 21 '18 at 16:43
  • @Galik thanks for pointing my mistake, original question has been updated. – Milen Marev Jun 22 '18 at 14:45

2 Answers2

2

std::to_string results in same string as printf("%f") would have output to console, and the latter uses default precision of 6 digits.

So your test setup is not suitable, you should rather use an array of strings instead.

Side note: Be aware that in C++, all of the double literals 0.0, 0.00, 0.000, ... result in the same double value (i. e. trailing zeros are just not relevant). Actually, you always have 64 bits to place your values in, distributed over sign bit, exponent and mantissa - and for all values with equal exponent, you have always exactly the same precision. Have a look at IEEE 754 for details.

Aconcagua
  • 24,880
  • 4
  • 34
  • 59
0

Your approach looks fine to me, if you use strings

bool checkFormatConsistency(const string& d) {
    static std::regex dbl("^[+-]?[0-9]+(\\.[0-9]{3,4})$");
    return std::regex_search(d, dbl);
}

int main() {
    vector<string> tests = {
        "0.00", "0.000", "0.0000", "0.00000", "10", "10.1", "-1000", "-99.99", "-345.236"
    };
    for (const string& test : tests) {
        cout << test << " -> " << (checkFormatConsistency(test) ? "ok" : "not ok") << endl;
    }

    return 0;
}

Output:

0.00 -> not ok
0.000 -> ok
0.0000 -> ok
0.00000 -> not ok
10 -> not ok
10.1 -> not ok
-1000 -> not ok
-99.99 -> not ok
-345.236 -> ok
Oneiros
  • 4,328
  • 6
  • 40
  • 69