0

I'm used to Python and I'm now learning C++ which is a bit more complicated to me. How can I modify the input so that it fits the description in the comment at the top of my code? I tried to include if (input[0]!='.' &&...) but it just returns 0. I want it to be included as part of the number. Same with the characters after the first character of the input.

I also don't know how I can separate numbers with more than three digits (starting from the end of the number obviously) with a comma (so 1000000 should be returned as 1,000,000).

/*
    * The first character can be a number, +, -, or a decimal point
    * All other characters can be numeric, a comma or a decimal point
    * Any commas must be in their proper location (ie, separating hundreds from thousands, from millions, etc)
    * No commas after the decimal point
    * Only one decimal point in the number
    * 
*/

#include <iostream>
#include <cmath>
#include <climits>
#include <string>

int ReadInt(std::string prompt);

int ReadInt(std::string prompt)
{
    std::string input;
    std::string convert;
    bool isValid=true;

    do {
        isValid=true;

            std::cout << prompt;
            std::cin >> input;


        if (input[0]!='.' && input[0]!='+' && input[0]!='-' && isdigit(input[0]) == 0) {
            std::cout << "Error! Input was not an integer.\n";
            isValid=false;
        }
        else {
            convert=input.substr(0,1);
        }

        long len=input.length();
        for (long index=1; index < len && isValid==true; index++) {
            if (input[index]==',') {
                ;
            }
            else if (isdigit(input[index]) == 0){
                std::cout << "Error! Input was not an integer.\n";
                isValid=false;
            }
            else if (input[index] == '.') {
                ;
            }
            else {
                convert += input.substr(index,1);
            }
        }
        } while (isValid==false);


    int returnValue=atoi(convert.c_str());
        return returnValue;
}


int main()
{
    int x=ReadInt("Enter a value: ");
    std::cout << "Value entered was " << x << std::endl;
    return 0;
}
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
userh16xx0
  • 37
  • 8
  • You might want to use a regex for matching a string like this. – cigien Oct 08 '20 at 03:47
  • I do agree with regex being a good option. However, I feel like I need to master the basics of C++ first. Is there a way I can do it with simple syntax? Using something similar to what I have maybe? – userh16xx0 Oct 08 '20 at 03:49
  • If you want to allow numbers with decimals, then you have to add the decimal point to the `convert` variable and use `atof` (or `std::stod`) to convert to a double. If it does not work, use a debugger to see where the execution fails your expectation. – Rene Oct 08 '20 at 04:33

1 Answers1

0

Writing parsing code is tricky. When parsing, it is easy to make a mess of the control flow. I suggest dividing up the I/O from the validation code: make a separate function bool IsVaildInt(const std::string& s) that returns whether s is a valid input, and do the prompts outside in a calling function.

It helps to think through systematically for every character what constitutes a valid input. If you are familiar with regexes, like cigien suggested, that may be a good way of organizing your approach even if you end up writing the parsing code by hand instead of using a regex library.

Here are the requirements that you posted:

* The first character can be a number, +, -, or a decimal point
* All other characters can be numeric, a comma or a decimal point
* Any commas must be in their proper location (ie, separating hundreds
  from thousands, from millions, etc)
* No commas after the decimal point
* Only one decimal point in the number

That's a lot of logic, but it's doable. It sounds like you are working on this as an exercise to master C++ basics, so I won't post any code. Instead, here's an outline for how I would approach this:

  1. Test that the first character is either 0-9, +, -, or decimal point. If it's not, return invalid.

  2. Search the string for whether it has a decimal point. If it does, remember its position.

  3. Loop over the remaining characters, in reverse starting from the last character.

    • Separate from the loop index, make a counter that says what the current digit place is (... -1 for tenths, 0 for ones, 1 for tens, 2 for hundreds, ...). If the string has a decimal point, use that vs. the string length to determine the digit place of the last character.

    • If a character is a comma, check that it is in a valid location compared to the current digit place. If not, return invalid.

    • Otherwise, if the character is a decimal point, it must be the one identified earlier. If not, that means there are multiple decimal points, so return invalid.

    • Otherwise, the character must be a digit 0-9, and the digit place counter should be incremented. If the character is not a digit, return invalid.

  4. Finally, if the loop makes it all the way through without hitting an error, return that the string is valid.

Pascal Getreuer
  • 2,906
  • 1
  • 5
  • 14