What can I use for input conversion instead of scanf?

前端 未结 8 1126
悲哀的现实
悲哀的现实 2020-11-22 13:27

I have very frequently seen people discouraging others from using scanf and saying that there are better alternatives. However, all I end up seeing is either

8条回答
  •  旧时难觅i
    2020-11-22 13:59

    Let's state the requirements of parsing as:

    • valid input must be accepted (and converted into some other form)

    • invalid input must be rejected

    • when any input is rejected, it is necessary to provide the user with a descriptive message that explains (in clear "easily understood by normal people who are not programmers" language) why it was rejected (so that people can figure out how to fix the problem)

    To keep things very simple, lets consider parsing a single simple decimal integer (that was typed in by the user) and nothing else. Possible reasons for the user's input to be rejected are:

    • the input contained unacceptable characters
    • the input represents a number that is lower than the accepted minimum
    • the input represents a number that is higher than the accepted maximum
    • the input represents a number that has a non-zero fractional part

    Let's also define "input contained unacceptable characters" properly; and say that:

    • leading whitespace and trailing whitespace will be ignored (e.g. "
      5 " will be treated as "5")
    • zero or one decimal point is allowed (e.g. "1234." and "1234.000" are both treated the same as "1234")
    • there must be at least one digit (e.g. "." is rejected)
    • no more than one decimal point is allowed (e.g. "1.2.3" is rejected)
    • commas that are not between digits will be rejected (e.g. ",1234" is rejected)
    • commas that are after a decimal point will be rejected (e.g. "1234.000,000" is rejected)
    • commas that are after another comma are rejected (e.g. "1,,234" is rejected)
    • all other commas will be ignored (e.g. "1,234" will be treated as "1234")
    • a minus sign that is not the first non-whitespace character is rejected
    • a positive sign that is not the first non-whitespace character is rejected

    From this we can determine that the following error messages are needed:

    • "Unknown character at start of input"
    • "Unknown character at end of input"
    • "Unknown character in middle of input"
    • "Number is too low (minimum is ....)"
    • "Number is too high (maximum is ....)"
    • "Number is not an integer"
    • "Too many decimal points"
    • "No decimal digits"
    • "Bad comma at start of number"
    • "Bad comma at end of number"
    • "Bad comma in middle of number"
    • "Bad comma after decimal point"

    From this point we can see that a suitable function to convert a string into an integer would need to distinguish between very different types of errors; and that something like "scanf()" or "atoi()" or "strtoll()" is completely and utterly worthless because they fail to give you any indication of what was wrong with the input (and use a completely irrelevant and inappropriate definition of what is/isn't "valid input").

    Instead, lets start writing something that isn't useless:

    char *convertStringToInteger(int *outValue, char *string, int minValue, int maxValue) {
        return "Code not implemented yet!";
    }
    
    int main(int argc, char *argv[]) {
        char *errorString;
        int value;
    
        if(argc < 2) {
            printf("ERROR: No command line argument.\n");
            return EXIT_FAILURE;
        }
        errorString = convertStringToInteger(&value, argv[1], -10, 2000);
        if(errorString != NULL) {
            printf("ERROR: %s\n", errorString);
            return EXIT_FAILURE;
        }
        printf("SUCCESS: Your number is %d\n", value);
        return EXIT_SUCCESS;
    }
    

    To meet the stated requirements; this convertStringToInteger() function is likely to end up being several hundred lines of code all by itself.

    Now, this was just "parsing a single simple decimal integer". Imagine if you wanted to parse something complex; like a list of "name, street address, phone number, email address" structures; or maybe like a programming language. For these cases you might need to write thousands of lines of code to create a parse that isn't a crippled joke.

    In other words...

    What can I use to parse input instead of scanf?

    Write (potentially thousands of lines) of code yourself, to suit your requirements.

提交回复
热议问题