Home > Back-end >  Input reading horizontally and vertically
Input reading horizontally and vertically

Time:12-18

I am trying to figure out how to read input multiple ways. Input can look like this.

N:{-4,2,1}
E:{1,1,9}
W:{-2,5,3}
S:{7,1}

or like this

E:{9,1,1}N:{1,2,-4}W:{3,5,-2}S:{7,1}

I added into my code checking for word END. Its supposed to be working on EOF but on my windows machine it doesnt work. So input END to signal END of input. So far I managed to get them both working separatly... But I need them to both at the same time.

char *skip_whitespace(char *str)
{
    //skip any leading whitespace characters
    while (*str == ' ' || *str == '\t')
        str  ;
    return str;
}
void read_tokens(int *north, int *west, int *east, int *south, int *north_size, int *west_size, int *east_size, int *south_size)
{
    //buffer for reading in input
    char buffer[MAX_TOKENS];
    //read in the input line by line
    while (fgets(buffer, MAX_TOKENS, stdin) != NULL)
    {
        //remove the newline character from the end of the line
        buffer[strcspn(buffer, "\n")] = 0;
        //check for the "END" string to end the input
        if (strcmp(buffer, "END") == 0)
            break;

        //split the line at the curly brace character
        char *direction_token = strtok(buffer, "{");
        char *tokens = strtok(NULL, "}");

        //get the direction
        char direction = direction_token[0];
        //skip any leading or trailing whitespace characters
        tokens = skip_whitespace(tokens);

        //split the tokens at each comma
        char *token = strtok(tokens, ",");


        //determine the direction and store the tokens in the appropriate array
        if (direction == 'N')
        {
            while (token != NULL)
            {
                //skip any leading or trailing whitespace characters
                token = skip_whitespace(token);
                //store the token in the array
                north[*north_size] = atoi(token);
                (*north_size)  ;
                //find the next token
                token = strtok(NULL, ",");
            }
        }
        else if (direction == 'W')
        {
            while (token != NULL)
            {
                //skip any leading or trailing whitespace characters
                token = skip_whitespace(token);
                //store the token in the array
                west[*west_size] = atoi(token);
                (*west_size)  ;
                //find the next token
                token = strtok(NULL, ",");
            }
        }
        else if (direction == 'E')
        {
            while (token != NULL)
            {
                //skip any leading or trailing whitespace characters
                token = skip_whitespace(token);
                //store the token in the array
                east[*east_size] = atoi(token);
                (*east_size)  ;
                //find the next token
                token = strtok(NULL, ",");
            }
        }
        else if (direction == 'S')
        {
            while (token != NULL)
            {
                //skip any leading or trailing whitespace characters
                token = skip_whitespace(token);
                //store the token in the array
                south[*south_size] = atoi(token);
                (*south_size)  ;
                //find the next token
                token = strtok(NULL, ",");
            }
        }
        else
        {
            //invalid direction = error
            printf("Nespravny vstup.\n");
        }
    }
}

Here is the main function. For anyone intrested here is calling and printing.

int main(void)
{
    //field for token values
    int north[MAX_TOKENS], west[MAX_TOKENS], east[MAX_TOKENS], south[MAX_TOKENS];
    //sizes of token value fields
    int north_size = 0, west_size = 0, east_size = 0, south_size = 0;
    printf("Input:\n");
    //fetch token values ​​from input
    read_tokens(north, west, east, south, &north_size, &west_size, &east_size, &south_size);



    printf("N: { ");
    for (int i = 0; i < north_size; i  )
        printf("%d, ", north[i]);
    printf("}\n");

    printf("W: { ");
    for (int i = 0; i < west_size; i  )
        printf("%d, ", west[i]);
    printf("}\n");

    printf("E: { ");
    for (int i = 0; i < east_size; i  )
        printf("%d, ", east[i]);
    printf("}\n");

    printf("S: { ");
    for (int i = 0; i < south_size; i  )
        printf("%d, ", south[i]);
    printf("}\n");
}

CodePudding user response:

You have an input format that permits optional whitespace, including newlines, between tokens. Your two examples differ only in that one makes use of that option and the other doesn't. In the most basic terms, then, the solution is to make your parser ignore (all) whitespace between tokens, too. Such a parser handles both forms of input presented, and other variants, too.

I do think, however, that fgets() is more a liability here than a help. Your input is not fundamentally line-oriented, and with fgets() you need to (but do not presently) watch out for and handle cases where a long line is split over two or more reads. I suggest tokenizing the input directly from the stream instead of first reading it into an intermediate buffer.

I know that scanf() gets a lot of hate, but it might serve your purpose pretty well here. It already knows how to skip whitespace, to recognize integers, and to match specific characters. Something along these lines, maybe:

while (1) {
    char direction;
    char delim;
    int result;

    // scan first part:
    result = scanf(" %c : %c", &direction, &delim);
    if (result == EOF) {
        // end of file
    } else if (result != 2 || !is_valid_direction(direction) || delim != '{') {
        // invalid input ...

        // ... or maybe (part of) an "END" keyword if you decide to
        // go ahead with that
    }

    // ... handle direction code ...

    do {
        // scan number
        int num;
        result = scanf("%d %c", &num, &delim);
        if (result != 2 || (delim != ',' && delim != '}')) {
            // invalid input ...
            // unless empty number lists are allowed: N:{}
        }

        // store number ...

    } while (delim == ',');
}

If you want to avoid scanf(), then you can do basically the same thing by reading one character at a time via getchar() or fgetc(). Or, yes, with fgets() too, provided you exercise sufficient care.

That's schematic, of course, not a full implementation of the needed parser

  • Related