Check if C ++ 98 string is number in scientific notation

I have a variable stringthat can be one of three things:

  • Number
  • Number in scientific notation
  • Text

In cases 1 and 3, I want to do nothing and transmit data. But in case 2, I need to convert it to a regular number. If I just always convert a variable to a regular number, then when it contains the actual text, it becomes "0". So I need to know if a string is a number in scientific notation. The obvious, dirty answer is this algorithm:

Iterate over the line until you see the numbers. If the first letter you see is "e" or "E", followed by either "+", or "-", or strictly more numbers, then this is a number in scientific notation, otherwise it is just a regular number or text.

But I assume that there is a better way to do this in C ++ 98 (without promotion). Is there a built-in method? Even if it is something that just uses try / catch.

EDIT The question was closed because it was supposed to be homework. This is not homework. Therefore, it should be renewed. Also, to clarify, I am forced to use C ++ 98 due to technical limitations.

, ( "" , ). , .

, :

1.453e-8
0.05843E5
8.43e6
5.2342E-7

, :

hello
03HX_12
8432
8432E
e-8
fail-83e1

enter image description here

+4
4

/: , :

.123
.123E3
123.
123.E+3

, ; . , , - - , :

.
.E+03

, , . , - ( NFA). . , .

, ad hoc , - : , , , , , . , :

have_digits_flag = false

while (string begins with a digit character) {
   have_digits_flag = true
   consume digit character 
}

if (!string begins with a decimal point)
   goto bad;
consume decimal point

while (string begins with digit) {
  consume digit
  have_digits_flag = true;
}

if (!have_digits_flag)
  goto bad; // we scanned just a decimal point not flanked by digits!

if (string begins with e or E) {
   consume character
   if (string begins with + or -)
     consume character
   if (!string begins with digit)
     goto bad;
   while (string begins with digit)
     consume character
}

if (string is empty)
  return true;

// oops, trailing junk

bad:
  return false;

"string ", , , . "string " .

" ", . std::string , .

, . , , , ad hoc- , lookahead. . .

+3

JSON . , "e" "-ee2".

:

  • "-",
  • ,

  • '0',
  • ( [1-9], [0-9])

  • ('.', [0-9])

  • (('e' 'E'), ('+' '-' ), [0-9])

, . RFC 7159, 6.

number = [ minus ] int [ frac ] [ exp ]
decimal-point = %x2E       ; .
digit1-9 = %x31-39         ; 1-9
e = %x65 / %x45            ; e E
exp = e [ minus / plus ] 1*DIGIT
frac = decimal-point 1*DIGIT
int = zero / ( digit1-9 *DIGIT )
minus = %x2D               ; -
plus = %x2B                ; +
zero = %x30                ; 0

, JSON ( , 64 , JSON , -2 ^ 53 + 1 2 ^ 53- 1):

template<typename InputIt,
         typename V = typename 
            std::iterator_traits<InputIt>::value_type>
static InputIt extractNumber(Variant& result, InputIt st, InputIt en);

template<typename InputIt, typename V>
InputIt JsonParser::extractNumber(Variant& result, InputIt st, InputIt en)
{
    if (st == en)
        parseError("Expected number at end of input");

    std::vector<V> text;

    auto accept = [&] {
        if (st == en)
            parseError("Expected number at end of input");
        text.emplace_back(*st++);
    };

    // -?(?:0|[1-9][0-9]*)(?:\.[0-9]+)?(?:[eE][+-]?[0-9]+)?
    // A    B C              D            E

    bool isFloatingPoint = false;

    if (*st == '-')
    {
        // A
        accept();
    }

    if (*st == '0')
    {
        // B
        accept();
    }
    else if (std::isdigit(*st, cLocale))
    {
        // C
        do
        {
            accept();
        }
        while (st != en && std::isdigit(*st, cLocale));
    }
    else
    {
        parseError("Invalid number");
    }

    if (st != en && *st == '.')
    {
        accept();

        isFloatingPoint = true;

        // D
        while (st != en && std::isdigit(*st, cLocale))
            accept();
    }

    if (st != en && (*st == 'E' || *st == 'e'))
    {
        isFloatingPoint = true;

        // E
        accept();

        if (st != en && (*st == '+' || *st == '-'))
            accept();

        if (st == en || !std::isdigit(*st, cLocale))
            parseError("Invalid number");

        while (st != en && std::isdigit(*st, cLocale))
            accept();
    }

    text.emplace_back(0);

    if (isFloatingPoint)
        result.assign(std::atof(text.data()));
    else
        result.assign(std::int64_t(std::atoll(text.data())));

    return st;
}

, st en , . .

+2
bool is_valid(std::string src){
    std::stringstream ss;
    ss << src;
    double d=0;
    ss >> d; 
    if (ss){
       return true;
    }
    else{
       return false;
    }
}

. ++ - .

+1

I ended up coding the FSA-based function, to which I turned my question. Plus a few tweaks based on koz info and tips (thanks), and minus some determinism, because it's code, and I can cut these corners :). It is bulky, but it is easy to understand, and it works. See Test Case Examples below code.

bool is_scientific_notation(string input) {
    int state = 0;
    for (string::size_type i = 0; i < input.size(); i++) {
        char character = input.at(i);
        //cout << character << endl;
        switch(state) {
            case 0: {
                // state 0: accept on '. or' '-' or digit
                if (character == '.') {
                    state = 3;
                } else if (character == '-') {
                    state = 1;
                } else if (isdigit(character)) {
                    state = 2;
                } else {
                    goto reject; // reject 
                }
                break;
            }
            case 1: {
                // state 1: accept on '. or digit
                if (character == '.') {
                    state = 3;
                } else if (isdigit(character)) {
                    state = 2;
                } else {
                    goto reject; // reject 
                }
                break;
            }
            case 2: {
                // state 2: accept on '.' or 'e' or 'E' digit
                if (character == '.') {
                    state = 4;
                } else if ((character == 'e') || (character == 'E')) {
                    state = 5;
                } else if (isdigit(character)) {
                    state = 2;
                } else {
                    goto reject; // reject 
                }
                break;
            }
            case 3: {
                // state 3: accept on digit
                if (isdigit(character)) {
                    state = 4;  
                } else {
                    goto reject; // reject 
                }
                break;
            }
            case 4: {
                // state 4: accept on 'e' or 'E' or digit
                if ((character == 'e') || (character == 'E')) {
                    state = 5;
                } else if (isdigit(character)) {
                    state = 4;  
                } else {
                    goto reject; // reject 
                }
                break;
            }
            case 5: {
                // state 5: accept on '+' or '-' or digit
                if ((character == '+') || (character == '-')) {
                    state = 6;
                } else if (isdigit(character)) {
                    state = 6;  
                } else {
                    goto reject; // reject 
                }
                break;
            }
            case 6: {
                // state 6: accept on digit
                if (isdigit(character)) {
                    state = 6;  
                } else {
                    goto reject; // reject 
                }
                break;
            }
        }
    }
    if (state == 6) {
        return true;
    } else {
        reject:
            return false;
    }
}

Tests:

// is_scientific_notation should return true
cout << ((is_scientific_notation("269E-9")) ? ("pass") : ("fail")) << endl;
cout << ((is_scientific_notation("269E9")) ? ("pass") : ("fail")) << endl;
cout << ((is_scientific_notation("269e-9")) ? ("pass") : ("fail")) << endl;
cout << ((is_scientific_notation("1.453e-8")) ? ("pass") : ("fail")) << endl;
cout << ((is_scientific_notation("8.43e+6")) ? ("pass") : ("fail")) << endl;
cout << ((is_scientific_notation("5.2342E-7")) ? ("pass") : ("fail")) << endl;
cout << ((is_scientific_notation(".2342E-7")) ? ("pass") : ("fail")) << endl;
cout << ((is_scientific_notation("8.e+2")) ? ("pass") : ("fail")) << endl;
cout << ((is_scientific_notation("-853.4E-2")) ? ("pass") : ("fail")) << endl;

// is_scientific_notation should return false
cout << ((is_scientific_notation("hello")) ? ("fail") : ("pass")) << endl;
cout << ((is_scientific_notation("03HX_12")) ? ("fail") : ("pass")) << endl;
cout << ((is_scientific_notation("8432")) ? ("fail") : ("pass")) << endl;
cout << ((is_scientific_notation("8432E")) ? ("fail") : ("pass")) << endl;
cout << ((is_scientific_notation("fail-83e1")) ? ("fail") : ("pass")) << endl;
cout << ((is_scientific_notation(".e8")) ? ("fail") : ("pass")) << endl;
cout << ((is_scientific_notation("E-8")) ? ("fail") : ("pass")) << endl;
cout << ((is_scientific_notation("2e.2")) ? ("fail") : ("pass")) << endl;
cout << ((is_scientific_notation("-E3")) ? ("fail") : ("pass")) << endl;

Conclusion:

pass
pass
pass
pass
pass
pass
pass
pass
pass
pass
pass
pass
pass
pass
pass
pass
pass
pass
0
source

All Articles